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

View File

@@ -0,0 +1,129 @@
#ifndef INCLUDE_MATERIAL_DATA_IMPLEMENTATION
# error Never include this file directly include 'material_data.hpp'
#endif
namespace zgl
{
inline material_data::material_data(
const std::optional<texture_handle>& texture_handle,
const std::optional<surface_properties_handle>& surface_properties_handle,
const std::optional<alpha_handle>& alpha_handle,
std::optional<texture_data>&& texture_data,
const material_component::flags components
) :
m_handle{
.texture = texture_handle,
.surface_properties = surface_properties_handle,
.alpha = alpha_handle
},
m_texture_data{ std::move(texture_data) },
m_component_types{ components } {}
inline material_data::material_data(material_data&& other) noexcept
{
m_handle = other.m_handle;
m_texture_data = std::move(other.m_texture_data);
m_component_types = other.m_component_types;
other.m_handle.texture = std::nullopt;
other.m_handle.surface_properties = std::nullopt;
other.m_handle.alpha = std::nullopt;
other.m_component_types = material_component::flags::none;
}
inline material_data& material_data::operator=(material_data&& other) noexcept
{
if (&other != this)
{
this->~material_data();
m_handle = other.m_handle;
m_texture_data = std::move(other.m_texture_data);
m_component_types = other.m_component_types;
other.m_handle.texture = std::nullopt;
other.m_handle.surface_properties = std::nullopt;
other.m_handle.alpha = std::nullopt;
other.m_component_types = material_component::flags::none;
}
return *this;
}
inline material_handle material_data::handle() const
{
return m_handle;
}
inline material_component::flags material_data::components() const
{
return m_component_types;
}
inline std::error_code material_data::build_from(
const std::optional<material_component::texture::value_type>& texture_opt,
const std::optional<material_component::surface_properties::value_type>& surface_properties_opt,
const std::optional<material_component::transparency::value_type>& transparency_opt,
const material_component::flags components,
material_data& dst_data
) {
auto texture_data_opt = std::optional<texture_data>{ std::nullopt };
auto texture_handle_opt = std::optional<texture_handle>{ std::nullopt };
if (texture_opt)
{
const auto& texture = *texture_opt;
auto texture_data = zgl::texture_data{};
if (const auto e = texture_data::build_from(
std::span(texture.cbegin(), texture.cend()),
GL_RGBA, GL_UNSIGNED_BYTE,
texture.width(),
texture.height(),
texture_data
)) {
return e;
}
texture_handle_opt.emplace(texture_data.handle());
texture_data_opt.emplace(std::move(texture_data));
}
auto surface_properties_data_opt = std::optional<surface_properties_handle>{ std::nullopt };
if (surface_properties_opt)
{
const auto& [ ambient, diffuse, specular, shininess ] = *surface_properties_opt;
surface_properties_data_opt.emplace(
glm::vec3{ ambient[0], ambient[1], ambient[2] },
glm::vec3{ diffuse[0], diffuse[1], diffuse[2] },
glm::vec3{ specular[0], specular[1], specular[2] },
shininess
);
}
auto alpha_data_opt = std::optional<alpha_handle>{ std::nullopt };
if (transparency_opt)
{
alpha_data_opt.emplace(1.0f - *transparency_opt);
}
/*dst_data = material_data{
texture_handle_opt,
surface_properties_data_opt,
alpha_data_opt,
std::move(texture_data_opt),
components
};*/
dst_data.m_handle.texture = texture_handle_opt;
dst_data.m_handle.surface_properties = surface_properties_data_opt;
dst_data.m_handle.alpha = alpha_data_opt;
dst_data.m_texture_data = std::move(texture_data_opt);
dst_data.m_component_types = components;
return {};
}
}

View File

@@ -0,0 +1,119 @@
#include "opengl/data/mesh_data.hpp"
#include "opengl/type_utils.hpp"
#include "opengl/error.hpp"
#include "GL/glew.h"
#include <algorithm>
#include "util/logger.hpp" // TODO remove
std::error_code zgl::mesh_data::build_from(
const std::span<const ztu::u8> vertex_buffer,
const std::span<const GLenum> component_types,
const std::span<const GLint> component_lengths,
const GLsizei stride,
const std::span<const ztu::u32> index_buffer,
const ztu::u32 material_id,
const components::mesh_vertex::flags components,
mesh_data& data
) {
if (not std::ranges::all_of(component_types, type_utils::is_valid_type))
{
ztu::logger::debug("not all types valid.");
return std::make_error_code(std::errc::invalid_argument);
}
const auto vertices_byte_count = vertex_buffer.size() * sizeof(std::uint8_t);
if (vertices_byte_count > std::numeric_limits<GLsizeiptr>::max())
{
return std::make_error_code(std::errc::value_too_large);
}
const auto indices_byte_count = index_buffer.size() * sizeof(ztu::u32);
if (indices_byte_count > std::numeric_limits<GLsizeiptr>::max())
{
return std::make_error_code(std::errc::value_too_large);
}
auto error = std::error_code{};
auto check_error = [&error, ec = static_cast<GLenum>(GL_NO_ERROR)]() mutable -> const std::error_code&
{
ec = glGetError();
if (ec != GL_NO_ERROR)
{
error = make_error_code(ec);
}
return error;
};
GLuint vao_id;
glGenVertexArrays(1, &vao_id);
glBindVertexArray(vao_id);
if (check_error()) return error;
ztu::logger::debug("Created mesh vao: % valid: %", vao_id, (bool)glIsVertexArray(vao_id));
GLuint vertex_buffer_id;
glGenBuffers(1, &vertex_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id);
glBufferData(
GL_ARRAY_BUFFER,
static_cast<GLsizeiptr>(vertices_byte_count),
vertex_buffer.data(),
GL_STATIC_DRAW
);
if (check_error()) return error;
GLuint index_buffer_id;
glGenBuffers(1, &index_buffer_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
static_cast<GLsizeiptr>(indices_byte_count),
index_buffer.data(),
GL_STATIC_DRAW
);
if (check_error()) return error;
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id);
if (check_error()) return error;
auto offset = GLsizei{ 0 };
for (std::size_t i{}; i != component_types.size(); ++i)
{
const auto type = component_types[i];
const auto length = component_lengths[i];
const auto byte_count = type_utils::size_of(type);
glVertexAttribPointer(
i,
length,
type,
GL_FALSE,
stride,
reinterpret_cast<GLvoid*>(offset)
);
glEnableVertexAttribArray(i);
if (check_error()) return error;
offset += length * byte_count;
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
data = mesh_data(
vertex_buffer_id,
index_buffer_id,
vao_id,
material_id,
components,
index_buffer.size()
);
return {};
}

View File

@@ -0,0 +1,90 @@
#ifndef INCLUDE_MESH_DATA_IMPLEMENTATION
# error Never include this file directly include 'mesh_data.hpp'
#endif
namespace zgl
{
inline mesh_data::mesh_data(
const GLuint vertex_vbo_id,
const GLuint index_vbo_id,
const GLuint vao_id,
const ztu::u32 material_id,
const components::mesh_vertex::flags components,
const GLsizei index_count
) :
m_handle{
.vao_id = vao_id,
.index_count = index_count
},
m_vertex_vbo_id{ vertex_vbo_id },
m_index_vbo_id{ index_vbo_id },
m_material_id{ material_id },
m_component_types{ components } {}
inline mesh_data& mesh_data::operator=(mesh_data&& other) noexcept
{
if (&other != this)
{
this->~mesh_data();
m_handle = other.m_handle;
m_vertex_vbo_id = other.m_vertex_vbo_id;
m_index_vbo_id = other.m_index_vbo_id;
m_material_id = other.m_material_id;
m_component_types = other.m_component_types;
other.m_handle.vao_id = 0;
other.m_handle.index_count = 0;
other.m_vertex_vbo_id = 0;
other.m_index_vbo_id = 0;
other.m_material_id = 0;
other.m_component_types = components::mesh_vertex::flags::none;
}
return *this;
}
inline mesh_data::mesh_data(mesh_data&& other) noexcept :
m_handle{ other.m_handle },
m_vertex_vbo_id{ other.m_vertex_vbo_id },
m_index_vbo_id{ other.m_index_vbo_id },
m_material_id{ other.m_material_id },
m_component_types{ other.m_component_types }
{
other.m_handle.vao_id = 0;
other.m_handle.index_count = 0;
other.m_vertex_vbo_id = 0;
other.m_index_vbo_id = 0;
other.m_material_id = 0;
other.m_component_types = components::mesh_vertex::flags::none;
}
inline mesh_data::~mesh_data() {
if (m_vertex_vbo_id) {
glDeleteBuffers(1, &m_vertex_vbo_id);
}
if (m_index_vbo_id) {
glDeleteBuffers(1, &m_index_vbo_id);
}
if (m_handle.vao_id) {
glDeleteVertexArrays(1, &m_handle.vao_id);
}
}
inline mesh_handle mesh_data::handle() const
{
return m_handle;
}
inline components::mesh_vertex::flags mesh_data::components() const
{
return m_component_types;
}
inline ztu::u32 mesh_data::material_id() const
{
return m_material_id;
}
}

View File

@@ -0,0 +1,99 @@
#include "opengl/data/point_cloud_data.hpp"
#include "opengl/type_utils.hpp"
#include "opengl/error.hpp"
#include <algorithm>
#include "GL/glew.h"
std::error_code zgl::point_cloud_data::build_from(
std::span<const std::uint8_t> point_buffer,
std::span<const GLenum> component_types,
std::span<const GLint> component_lengths,
GLsizei stride,
point_cloud_data& data
) {
if (not std::ranges::all_of(component_types, type_utils::is_valid_type))
{
return std::make_error_code(std::errc::invalid_argument);
}
const auto points_byte_count = point_buffer.size() * sizeof(std::uint8_t);
if (points_byte_count > std::numeric_limits<GLsizeiptr>::max())
{
return std::make_error_code(std::errc::value_too_large);
}
auto error = std::error_code{};
auto check_error = [&error, ec = static_cast<GLenum>(GL_NO_ERROR)]() mutable -> const std::error_code&
{
ec = glGetError();
if (ec != GL_NO_ERROR) {
error = make_error_code(ec);
}
return error;
};
ztu::u32 vao_id;
glGenVertexArrays(1, &vao_id);
if (check_error()) return error;
glBindVertexArray(vao_id);
if (check_error()) return error;
ztu::u32 vertex_buffer_id;
glGenBuffers(1, &vertex_buffer_id);
if (check_error()) return error;
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id);
if (check_error()) return error;
glBufferData(
GL_ARRAY_BUFFER,
static_cast<GLsizeiptr>(points_byte_count),
point_buffer.data(),
GL_STATIC_DRAW
);
if (check_error()) return error;
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id);
if (check_error()) return error;
auto offset = GLsizei{ 0 };
for (std::size_t i{}; i != component_types.size(); ++i)
{
const auto type = component_types[i];
const auto length = component_lengths[i];
const auto byte_count = type_utils::size_of(type);
glVertexAttribPointer(
i,
length,
type,
GL_FALSE,
stride,
reinterpret_cast<GLvoid*>(offset)
);
if (check_error()) return error;
glEnableVertexAttribArray(i);
if (check_error()) return error;
offset += length * byte_count;
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
if (check_error()) return error;
glBindVertexArray(0);
if (check_error()) return error;
data = point_cloud_data(
vertex_buffer_id,
vao_id,
point_buffer.size()
);
return {};
}

View File

@@ -0,0 +1,66 @@
#ifndef INCLUDE_POINT_CLOUD_DATA_IMPLEMENTATION
# error Never include this file directly include 'point_cloud_data.hpp'
#endif
namespace zgl
{
inline point_cloud_data::point_cloud_data(
const GLuint vertex_vbo_id,
const GLuint vao_id,
const GLsizei point_count
) :
m_handle{
.vao_id = vao_id,
.point_count = point_count
},
m_vertex_vbo_id{ vertex_vbo_id } {}
inline point_cloud_data::point_cloud_data(point_cloud_data&& other) noexcept :
m_handle{ other.m_handle },
m_vertex_vbo_id{ other.m_vertex_vbo_id }
{
other.m_handle.vao_id = 0;
other.m_handle.point_count = 0;
other.m_vertex_vbo_id = 0;
}
inline point_cloud_data& point_cloud_data::operator=(point_cloud_data&& other) noexcept
{
if (&other != this)
{
this->~point_cloud_data();
m_handle = other.m_handle;
m_vertex_vbo_id = other.m_vertex_vbo_id;
other.m_handle.vao_id = 0;
other.m_handle.point_count = 0;
other.m_vertex_vbo_id = 0;
}
return *this;
}
inline point_cloud_data::~point_cloud_data()
{
if (m_vertex_vbo_id)
{
glDeleteBuffers(1, &m_vertex_vbo_id);
}
if (m_handle.vao_id)
{
glDeleteVertexArrays(1, &m_handle.vao_id);
}
}
inline point_cloud_handle point_cloud_data::handle() const
{
return m_handle;
}
inline components::point_cloud_vertex::flags point_cloud_data::components() const
{
return m_component_types;
}
}

View File

@@ -0,0 +1,46 @@
#include "opengl/data/shader_data.hpp"
#include "GL/glew.h"
#include "opengl/error.hpp"
#include "util/logger.hpp"
namespace zgl
{
std::error_code shader_data::build_from(
const GLenum type,
const std::string& source,
shader_data& data
) {
auto shader_id = GLuint{ 0 };
if (not source.empty())
{
shader_id = glCreateShader(type);
// Curious choice to take lists as parameters...
const auto first_list_element = source.c_str();
const auto first_list_element_len = static_cast<GLint>(source.length());
glShaderSource(shader_id, 1, &first_list_element, &first_list_element_len);
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::warn("Error while compiling shader:\n%", log);
return std::make_error_code(std::errc::invalid_argument);
}
}
data = shader_data{ shader_id, type };
return {};
}
}

View File

@@ -0,0 +1,47 @@
#ifndef INCLUDE_SHADER_DATA_IMPLEMENTATION
# error Never include this file directly include 'shader_data.hpp'
#endif
namespace zgl
{
inline shader_data::shader_data(const GLuint shader_id, const GLenum type)
: m_handle{ shader_id }, m_type{ type } {}
inline shader_data::shader_data(shader_data&& other) noexcept
{
m_handle = other.m_handle;
m_type = other.m_type;
other.m_handle.shader_id = 0;
other.m_type = GL_INVALID_ENUM;
}
inline shader_data& shader_data::operator=(shader_data&& other) noexcept
{
if (&other != this)
{
this->~shader_data();
m_handle = other.m_handle;
m_type = other.m_type;
other.m_handle.shader_id = 0;
other.m_type = GL_INVALID_ENUM;
}
return *this;
}
inline shader_data::~shader_data()
{
if (m_handle.shader_id)
{
glDeleteShader(m_handle.shader_id);
}
m_type = GL_INVALID_ENUM;
}
inline shader_handle shader_data::handle() const
{
return m_handle;
}
}

View File

@@ -0,0 +1,90 @@
#include "opengl/data/shader_program_data.hpp"
#include <fstream>
#include "GL/glew.h"
#include <glm/gtc/type_ptr.hpp>
#include "util/for_each.hpp"
#include "util/logger.hpp"
#include "opengl/error.hpp"
namespace zgl
{
std::error_code shader_program_data::build_from(
const shader_handle& vertex_shader,
const shader_handle& geometry_shader,
const shader_handle& fragment_shader,
shader_program_data& data
) {
auto error = std::error_code{};
auto check_error = [&error, ec = static_cast<GLenum>(GL_NO_ERROR)]() mutable -> std::error_code&
{
ec = glGetError();
if (ec != GL_NO_ERROR) {
error = make_error_code(ec);
}
return error;
};
const auto program_id = glCreateProgram();
if (check_error()) return error;
using namespace std::string_view_literals;
constexpr auto shader_names = std::array{
"vertex"sv, "geometry"sv, "fragment"sv
};
for (const auto& [shader, name] : {
std::tie(vertex_shader, shader_names[0]),
std::tie(geometry_shader, shader_names[1]),
std::tie(fragment_shader, shader_names[2])
}) {
if (shader.shader_id) {
glAttachShader(program_id, shader.shader_id);
} else {
ztu::logger::warn("Using default % shader", name);
}
}
glLinkProgram(program_id);
if (check_error()) return error;
auto status = GLint{ GL_FALSE };
glGetProgramiv(program_id, GL_LINK_STATUS, &status);
if (check_error()) return error;
if (status == GL_FALSE) {
GLint log_length{};
glGetShaderiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
auto log = std::string(log_length, ' ');
glGetProgramInfoLog(program_id, log_length, nullptr, log.data());
ztu::logger::warn("Error while linking program: [%] %", log_length, log);
return std::make_error_code(std::errc::io_error);
}
glUseProgram(0);
ztu::for_each::argument(
[&](const auto& shader)
{
if (shader.shader_id) {
glDetachShader(program_id, shader.shader_id);
}
return true;
},
vertex_shader, geometry_shader, fragment_shader
);
data = shader_program_data{ program_id };
return {};
}
}

View File

@@ -0,0 +1,45 @@
#ifndef INCLUDE_SHADER_PROGRAM_DATA_IMPLEMENTATION
# error Never include this file directly include 'shader_program_data.hpp'
#endif
#include <glm/gtc/type_ptr.hpp>
#include "util/for_each.hpp"
#include "util/logger.hpp"
#include "opengl/error.hpp"
namespace zgl
{
inline shader_program_data::shader_program_data(GLuint program_id)
: m_handle{ program_id } {}
inline shader_program_data::shader_program_data(shader_program_data&& other) noexcept
{
m_handle = other.m_handle;
other.m_handle.program_id = 0;
}
inline shader_program_data& shader_program_data::operator=(shader_program_data&& other) noexcept
{
if (&other != this)
{
this->~shader_program_data();
m_handle = other.m_handle;
other.m_handle.program_id = 0;
}
return *this;
}
inline shader_program_data::~shader_program_data()
{
if (m_handle.program_id) {
glDeleteProgram(m_handle.program_id);
}
}
[[nodiscard]] inline shader_program_handle shader_program_data::handle() const
{
return m_handle;
}
}

View File

@@ -0,0 +1,79 @@
#ifndef INCLUDE_TEXTURE_DATA_IMPLEMENTATION
# error Never include this file directly include 'texture_data.hpp'
#endif
namespace zgl
{
inline texture_data::texture_data(const GLuint texture_id)
: m_handle{ texture_id } {}
inline texture_data::texture_data(texture_data&& other) noexcept
: m_handle{ other.m_handle }
{
other.m_handle.texture_id = 0;
}
inline texture_data& texture_data::operator=(texture_data&& other) noexcept
{
if (&other != this)
{
this->~texture_data();
m_handle = other.m_handle;
other.m_handle.texture_id = 0;
}
return *this;
}
template<typename T>
std::error_code texture_data::build_from(
std::span<const T> buffer,
const GLenum format,
const GLenum type,
const GLsizei width,
const GLsizei height,
texture_data& data
) {
GLuint texture_id;
glGenTextures(1, &texture_id);
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,
width,
height,
0,
format, type,
buffer.data()
);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
data = texture_data(texture_id);
return {};
}
inline texture_data::~texture_data()
{
if (m_handle.texture_id)
{
glDeleteTextures(1, &m_handle.texture_id);
}
}
inline texture_handle texture_data::handle() const
{
return { m_handle.texture_id };
}
}

View File

@@ -0,0 +1,152 @@
#include "opengl/handles/shader_program_handle.hpp"
#include <string_view>
// TODO remove
#include "opengl/error.hpp"
#include "util/logger.hpp"
namespace zgl
{
shader_program_handle::attribute_support_type shader_program_handle::check_attribute_support(
const std::span<const shader_program_variable> attributes
) const {
auto attribute_candidates = attribute_support_type{};
auto error = std::error_code{};
auto check_error = [&error, ec = static_cast<GLenum>(GL_NO_ERROR)]() mutable -> std::error_code&
{
ec = glGetError();
if (ec != GL_NO_ERROR) {
error = make_error_code(ec);
}
return error;
};
auto curr_attribute_flag = attribute_support_type{ 1 };
for (const auto& attribute : attributes) {
const auto location = glGetAttribLocation(program_id, attribute.name);
if (location == attribute.info.location)
{
attribute_candidates |= curr_attribute_flag;
}
curr_attribute_flag <<= 1;
}
auto supported_attributes = attribute_support_type{};
GLint count;
glGetProgramiv(program_id, GL_ACTIVE_ATTRIBUTES, &count);
if (check_error()) ztu::logger::error("GL_err: %", error.message());
for (GLint i{}; i != count and attribute_candidates; ++i)
{
GLenum type;
GLint size;
GLsizei name_length;
auto name = std::array<char, 256>{};
glGetActiveAttrib(
program_id, i,
name.size(),
&name_length,
&size, &type,
name.data()
);
if (check_error()) ztu::logger::error("GL_err: %", error.message());
const auto name_view = std::string_view(name.data(), name_length);
auto attribute_index = attribute_support_type{};
for (auto candidates = attribute_candidates; candidates; candidates >>= 1) {
if (candidates & 1)
{
const auto& attribute = attributes[attribute_index];
if (type == attribute.info.type and name_view == attribute.name)
{
const auto new_uniform_flag = attribute_support_type{ 1 } << attribute_index;
supported_attributes |= new_uniform_flag;
attribute_candidates ^= new_uniform_flag;
}
}
++attribute_index;
}
}
return supported_attributes;
}
shader_program_handle::uniform_support_type shader_program_handle::check_uniform_support(
const std::span<const shader_program_variable> uniforms
) const {
auto uniform_candidates = uniform_support_type{};
auto error = std::error_code{};
auto check_error = [&error, ec = static_cast<GLenum>(GL_NO_ERROR)]() mutable -> std::error_code&
{
ec = glGetError();
if (ec != GL_NO_ERROR) {
error = make_error_code(ec);
}
return error;
};
auto curr_uniform_flag = uniform_support_type{ 1 };
for (const auto& uniform : uniforms)
{
const auto location = glGetUniformLocation(program_id, uniform.name);
if (location == uniform.info.location)
{
uniform_candidates |= curr_uniform_flag;
ztu::logger::debug("[%] '%': %.", program_id, uniform.name, location);
}
else
{
ztu::logger::debug("Expected '%' at % but was %.", uniform.name, uniform.info.location, location);
}
curr_uniform_flag <<= 1;
}
auto supported_uniforms = uniform_support_type{};
GLint count;
glGetProgramiv(program_id, GL_ACTIVE_UNIFORMS, &count);
if (check_error()) ztu::logger::error("GL_err: %", error.message());
for (GLint i{}; i != count and uniform_candidates; ++i)
{
GLenum type;
GLint size;
GLsizei name_length;
auto name = std::array<char, 256>{};
glGetActiveUniform(
program_id, i,
name.size(),
&name_length,
&size, &type,
name.data()
);
if (check_error()) ztu::logger::error("GL_err: %", error.message());
const auto name_view = std::string_view(name.data(), name_length);
auto uniform_index = uniform_support_type{};
for (auto candidates = uniform_candidates; candidates; candidates >>= 1)
{
if (candidates & 1)
{
const auto& uniform = uniforms[uniform_index];
if (type == uniform.info.type and name_view == uniform.name)
{
const auto new_uniform_flag = uniform_support_type{ 1 } << uniform_index;
supported_uniforms |= new_uniform_flag;
uniform_candidates ^= new_uniform_flag;
}
}
++uniform_index;
}
}
return supported_uniforms;
}
}

View File

@@ -0,0 +1,195 @@
#include "opengl/shader_program_lookup.hpp"
#include <algorithm>
#include <bitset>
#include "util/logger.hpp" // TODO remove
namespace zgl
{
void shader_program_lookup::add(
const shader_program_handle& shader_program_handle,
const std::span<const shader_program_variable> all_attributes,
const std::span<const shader_program_variable> all_uniforms
) {
const auto attributes = shader_program_handle.check_attribute_support(all_attributes);
const auto uniforms = shader_program_handle.check_uniform_support(all_uniforms);
ztu::logger::debug("add [%] uniforms: % attributes: %",
shader_program_handle.program_id,
std::bitset<32>(uniforms),
std::bitset<32>(attributes)
);
const auto lower_uniform = std::ranges::lower_bound(
m_mesh_shader_program_uniforms,
uniforms
);
const auto upper_uniform = std::find_if(
lower_uniform, m_mesh_shader_program_uniforms.end(),
[&](const auto& curr_uniforms) {
return curr_uniforms > uniforms;
}
);
const auto lower_index = lower_uniform - m_mesh_shader_program_uniforms.begin();
const auto upper_index = upper_uniform - m_mesh_shader_program_uniforms.begin();
const auto lower_attribute = m_mesh_shader_program_attributes.begin() + lower_index;
const auto upper_attribute = m_mesh_shader_program_attributes.begin() + upper_index;
const auto attribute_it = std::upper_bound(
lower_attribute, upper_attribute,
attributes,
[](const auto& attributes, const auto& entry) {
return attributes < entry.attributes;
}
);
const auto index = attribute_it - m_mesh_shader_program_attributes.begin();
const auto attribute_locations = attribute_location_flags(
attributes, all_attributes
);
m_mesh_shader_program_uniforms.insert(
m_mesh_shader_program_uniforms.begin() + index, uniforms
);
m_mesh_shader_program_attributes.emplace(
attribute_it, attributes, attribute_locations
);
m_mesh_shader_programs.insert(
m_mesh_shader_programs.begin() + index, shader_program_handle
);
}
std::optional<shader_program_handle> shader_program_lookup::find(
shader_program_handle::attribute_support_type attributes,
shader_program_handle::uniform_support_type uniforms,
const std::span<const shader_program_variable> all_attributes
) const {
const auto lower_uniform = std::ranges::lower_bound(
m_mesh_shader_program_uniforms,
uniforms
);
if (
lower_uniform == m_mesh_shader_program_uniforms.end() or
*lower_uniform != uniforms
) {
return std::nullopt;
}
const auto upper_uniform = std::find_if(
lower_uniform, m_mesh_shader_program_uniforms.end(),
[&](const auto& curr_uniforms) {
return curr_uniforms > uniforms;
}
);
const auto lower_index = lower_uniform - m_mesh_shader_program_uniforms.begin();
const auto upper_index = upper_uniform - m_mesh_shader_program_uniforms.begin();
const auto relevant_attributes = std::span(
m_mesh_shader_program_attributes.begin() + lower_index,
m_mesh_shader_program_attributes.begin() + upper_index
);
const auto upper_attribute = std::upper_bound(
relevant_attributes.begin(), relevant_attributes.end(),
attributes,
[](const auto& attributes, const auto& entry) {
return attributes < entry.attributes;
}
);
auto entry_it = std::prev(upper_attribute);
if (
upper_attribute != relevant_attributes.begin() and
entry_it->attributes != attributes
) {
const auto locations = attribute_location_flags(attributes, all_attributes);
auto found_match = false;
while (entry_it != relevant_attributes.begin())
{
--entry_it;
const auto& [ curr_attributes, curr_locations ] = *entry_it;
// The candidate may not support additional attributes
if (curr_attributes & ~attributes)
{
continue;
}
// The candidate may not be missing 'inner' attributes,
// as this creates location alignment problems.
const auto higher_neighbour_matched = (curr_locations & locations) >> 1;
const auto bubbles = higher_neighbour_matched & ~curr_locations;
if (not bubbles)
{
found_match = true;
break;
}
}
if (not found_match)
{
return std::nullopt;
}
}
const auto shader_program_index = entry_it.base() - m_mesh_shader_program_attributes.begin().base();
return m_mesh_shader_programs[shader_program_index];
}
shader_program_lookup::attribute_locations_type shader_program_lookup::attribute_location_flags(
shader_program_handle::attribute_support_type attributes,
std::span<const shader_program_variable> all_attributes
) {
auto location_flags = ztu::u32{ 0 };
auto index = std::size_t{};
while (attributes)
{
if (attributes & 1)
{
const auto location = all_attributes[index].info.location;
location_flags |= attribute_locations_type{ 1 } << location;
}
attributes >>= 1;
++index;
}
return location_flags;
}
void shader_program_lookup::print() {
for (std::size_t i{}; i != m_mesh_shader_program_uniforms.size(); ++i) {
const auto shader = m_mesh_shader_programs[i];
const auto uniforms = m_mesh_shader_program_uniforms[i];
const auto [ attributes, locations ] = m_mesh_shader_program_attributes[i];
ztu::logger::debug("[%] uniforms: % attributes: % locations: %",
shader.program_id,
std::bitset<32>(uniforms),
std::bitset<32>(attributes),
std::bitset<32>(locations)
);
}
}
}