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,341 @@
#include "rendering/batch_renderers/mesh_batch_renderer.hpp"
#include "shader_program/uniforms/mesh_uniforms.hpp"
#include "util/unroll_bool_template.hpp"
#include "util/logger.hpp" // TODO remove
#include <bitset> // TODOE remove
namespace rendering
{
mesh_batch_renderer::mesh_batch_renderer(int render_mode_count)
: m_render_mode_count{ render_mode_count } {};
std::pair<std::size_t, bool> mesh_batch_renderer::lookup_batch(
const batch_components_type& batch_components
) const {
const auto component_it = std::upper_bound(
m_component_lookup.begin(), m_component_lookup.end(),
batch_components,
[](const auto& components, const auto& entry)
{
return components < entry.first;
}
);
const auto index = component_it - m_component_lookup.begin();
const auto match = (
index != 0 and m_component_lookup[index - 1].first == batch_components
);
return { index - static_cast<std::size_t>(match), match };
}
std::optional<mesh_batch_renderer::id_type> mesh_batch_renderer::add(
const batch_components_type& batch_component,
const zgl::mesh_handle& mesh,
const aabb& bounding_box,
const zgl::model_matrix_handle& transform,
const zgl::material_handle& material,
const shader_program_lookups::mesh_lookup& shader_program_lookup
) {
const auto [ lookup_index, lookup_match ] = lookup_batch(batch_component);
std::size_t batch_index;
batch_id_type batch_id;
if (lookup_match)
{
batch_index = m_component_lookup[lookup_index].second;
batch_id = m_id_lookup[batch_index];
}
else
{
auto base_requirements = requirements::mesh::flags::position;
const auto [ vertex_comps, material_comps ] = batch_component;
// If no texture is provided, the uniform color is provided by ambient light.
if ((material_comps & material_component::flags::texture) == material_component::flags::none)
{
base_requirements |= requirements::mesh::flags::uniform_color;
}
ztu::logger::debug("vertex_comps: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(vertex_comps)) });
ztu::logger::debug("material_comps: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(material_comps)) });
ztu::logger::debug("lit reqs: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(shader_program::capabilities::mesh::lit.uniforms)) });
for (std::size_t i{}; i != requirements::mesh::all.size(); ++i)
{
const auto& requirement = requirements::mesh::all[i];
if (
(
requirement.vertex_requirements != components::mesh_vertex::flags::none and
(vertex_comps & requirement.vertex_requirements) == requirement.vertex_requirements
)
and
(
requirement.material_requirements != material_component::flags::none and
(material_comps & requirement.material_requirements) == requirement.material_requirements
)
) {
base_requirements |= requirements::mesh::flags{ 1 << i };
}
}
ztu::logger::debug("base reqs: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(base_requirements)) });
const auto base_shader = shader_program_lookup.find(base_requirements);
if (not base_shader)
{
ztu::logger::warn("Could not find base shader!");
return std::nullopt;
}
const auto point_shader = shader_program_lookup.find(base_requirements | requirements::mesh::flags::point);
if (not point_shader)
{
ztu::logger::warn("Could not find point shader!");
return std::nullopt;
}
const auto lit_shader = shader_program_lookup.find(base_requirements | requirements::mesh::flags::lit);
if (not lit_shader)
{
ztu::logger::warn("Could not find lit shader!");
return std::nullopt;
}
auto shader_programs = std::array{
*base_shader,
*point_shader,
*base_shader,
*lit_shader
};
ztu::logger::debug(
"shaders: % % %",
base_shader->program_id,
point_shader->program_id,
lit_shader->program_id
);
batch_index = m_batches.size();
batch_id = m_next_batch_id++;
m_batches.emplace_back(batch_type{}, batch_component);
m_id_lookup.push_back(batch_id);
m_component_lookup.emplace(m_component_lookup.begin() + lookup_index, batch_component, batch_index);
m_shader_programs.insert(
m_shader_programs.begin() + lookup_index,
shader_programs.begin(), shader_programs.end()
);
}
auto& batch = m_batches[batch_index].first;
const auto mesh_id = batch.add(mesh, bounding_box, transform, material);
return id_type{ batch_id, mesh_id };
}
std::optional<aabb> mesh_batch_renderer::bounding_box(id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id.first);
if (lookup_it == m_id_lookup.end())
{
return std::nullopt;
}
const auto batch_index = lookup_it - m_id_lookup.begin();
auto& batch = m_batches[batch_index].first;
return batch.bounding_box(id.second);
}
bool mesh_batch_renderer::remove(const id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id.first);
if (lookup_it == m_id_lookup.end())
{
return false;
}
const auto batch_index = lookup_it - m_id_lookup.begin();
auto& batch = m_batches[batch_index].first;
// If batches can be removed the indices in m_component_lookup need to be changed.
return batch.remove(id.second);
}
template<bool Textured, bool Lit, bool Alpha>
void render_mesh_batch(
const zgl::shader_program_handle& shader_program,
const mesh_batch& batch,
const glm::mat4& vp_matrix,
const glm::mat4& view_matrix,
const GLenum draw_mode
) {
const auto meshes = batch.meshes();
const auto transforms = batch.transforms();
const auto textures = batch.textures();
const auto surface_properties = batch.surface_properties();
const auto alphas = batch.alphas();
/*ztu::logger::debug("meshes: %", meshes.size());
ztu::logger::debug("transforms: %", transforms.size());
ztu::logger::debug("textures: %", textures.size());
ztu::logger::debug("surface_properties: %", surface_properties.size());
ztu::logger::debug("alphas: %", alphas.size());
ztu::logger::debug("textured: % alpha: % lit: %", Textured, Alpha, Lit);*/
namespace uniforms = shader_program::uniforms::mesh;
for (std::size_t i{}; i != meshes.size(); ++i)
{
//ztu::logger::debug("Mesh: %", i);
const auto& mesh = meshes[i];
const auto& model_matrix = transforms[i];
const auto mvp_matrix = vp_matrix * model_matrix;
shader_program.set_uniform<uniforms::mvp.info>(mvp_matrix);
if constexpr (Textured)
{
textures[i].bind();
}
if constexpr (Lit)
{
shader_program.set_uniform<uniforms::model_matrix.info>(model_matrix);
// TODO more efficient set
const auto& properties = surface_properties[i];
shader_program.set_uniform<uniforms::ambient_filter.info>(properties.ambient_filter);
shader_program.set_uniform<uniforms::diffuse_filter.info>(properties.diffuse_filter);
shader_program.set_uniform<uniforms::specular_filter.info>(properties.specular_filter);
shader_program.set_uniform<uniforms::shininess.info>(properties.shininess);
}
if constexpr (Alpha)
{
shader_program.set_uniform<uniforms::alpha.info>(alphas[i]);
}
//ztu::logger::debug("vao: % valid: %%", mesh.vao_id, std::boolalpha, (bool)glIsVertexArray(mesh.vao_id));
mesh.bind();
//ztu::logger::debug("glDrawElements(%, %)", draw_mode, mesh.index_count);
glDrawElements(draw_mode, mesh.index_count, GL_UNSIGNED_INT, nullptr);
//ztu::logger::debug("done");
}
}
void mesh_batch_renderer::render(
const modes::mesh render_mode,
const glm::mat4& vp_matrix,
const glm::mat4& view_matrix,
const glm::vec3& view_pos,
const lighting_setup& lights
) {
namespace uniforms = shader_program::uniforms::mesh;
const auto render_mode_index = static_cast<int>(render_mode);
const auto lines = render_mode == modes::mesh::wire_frame;
const auto points = render_mode == modes::mesh::points;
const auto lit = render_mode == modes::mesh::lit_faces;
for (std::size_t i{}; i != m_batches.size(); ++i) {
//ztu::logger::debug("batch: %", i);
const auto& [ batch, batch_components ] = m_batches[i];
const auto [ vertex_components, material_components ] = batch_components;
const auto textured = (
(vertex_components & components::mesh_vertex::flags::tex_coord) != components::mesh_vertex::flags::none
and (material_components & material_component::flags::texture) != material_component::flags::none
);
const auto alpha = (
(material_components & material_component::flags::transparency) != material_component::flags::none
);
const auto draw_mode = points ? GLenum{ GL_POINTS } : GLenum{ GL_TRIANGLES };
const auto& shader_program = m_shader_programs[i * m_render_mode_count + render_mode_index];
//ztu::logger::debug("shader_program: % valid: %%", shader_program.program_id, std::boolalpha, (bool)glIsProgram(shader_program.program_id));
shader_program.bind();
if (lit)
{
// TODO set more efficiently
shader_program.set_uniform<uniforms::view_pos.info>(view_pos);
shader_program.set_uniform<uniforms::point_light_direction.info>(lights.point_light_direction);
shader_program.set_uniform<uniforms::point_light_color.info>(lights.point_light_color);
shader_program.set_uniform<uniforms::ambient_light_color.info>(lights.ambient_light_color);
}
if (textured)
{
constexpr auto texture_unit = 0;
glActiveTexture(GL_TEXTURE0 + texture_unit);
shader_program.set_uniform<uniforms::tex.info>(texture_unit);
}
else
{
shader_program.set_uniform<uniforms::color.info>(glm::vec4(lights.ambient_light_color, 1.0f));
}
if (lines)
{
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
}
unroll_bool_function_template(
[&]<bool Textured, bool Lit, bool Alpha>() {
render_mesh_batch<Textured, Lit, Alpha>(
shader_program,
batch,
vp_matrix,
view_matrix,
draw_mode
);
},
textured, lit, alpha
);
if (lines)
{
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
}
}
zgl::texture_handle::unbind();
zgl::mesh_handle::unbind();
zgl::shader_program_handle::unbind();
}
}

View File

@@ -0,0 +1,243 @@
#include "rendering/batch_renderers/point_cloud_batch_renderer.hpp"
#include <algorithm>
#include "rendering/requirements/point_cloud_requirements.hpp"
#include "shader_program/uniforms/point_cloud_uniforms.hpp"
#include "util/unroll_bool_template.hpp"
namespace rendering
{
point_cloud_batch_renderer::point_cloud_batch_renderer(int render_mode_count)
: m_render_mode_count{ render_mode_count } {};
std::pair<std::size_t, bool> point_cloud_batch_renderer::lookup_batch(
const batch_components_type& batch_component
) const {
const auto component_it = std::upper_bound(
m_component_lookup.begin(), m_component_lookup.end(),
batch_component,
[](const auto& batch_component, const auto& entry)
{
return batch_component < entry.first;
}
);
const auto index = component_it - m_component_lookup.begin();
const auto match = (
index == 0 or m_component_lookup[index - 1].first == batch_component
);
return { index - static_cast<std::size_t>(match), match };
}
std::optional<point_cloud_batch_renderer::id_type> point_cloud_batch_renderer::add(
batch_components_type batch_components,
const zgl::point_cloud_handle& point_cloud,
const aabb& bounding_box,
const zgl::model_matrix_handle& transform,
const shader_program_lookups::point_cloud_lookup& shader_program_lookup
) {
const auto [ lookup_index, lookup_match ] = lookup_batch(batch_components);
std::size_t batch_index;
batch_id_type batch_id;
if (lookup_match) {
batch_index = m_component_lookup[lookup_index].second;
batch_id = m_id_lookup[batch_index];
}
else
{
auto base_requirements = requirements::point_cloud::flags{};
const auto vertex_comps = batch_components;
for (std::size_t i{}; i != requirements::point_cloud::all.size(); ++i)
{
const auto& requirement = requirements::point_cloud::all[i];
if (
(vertex_comps & requirement.vertex_requirements) != components::point_cloud_vertex::flags::none
) {
base_requirements |= requirements::point_cloud::flags{ 1 << i };
}
}
const auto uniform_color_shader = shader_program_lookup.find(
base_requirements | requirements::point_cloud::flags::uniform_color
);
if (not uniform_color_shader)
{
return std::nullopt;
}
const auto rainbow_shader = shader_program_lookup.find(
base_requirements | requirements::point_cloud::flags::rainbow
);
if (not rainbow_shader)
{
return std::nullopt;
}
auto shader_programs = std::array{
*uniform_color_shader,
*rainbow_shader
};
batch_index = m_batches.size();
batch_id = m_next_batch_id++;
m_batches.emplace_back(batch_type{}, batch_components);
m_id_lookup.push_back(batch_id);
m_component_lookup.emplace(m_component_lookup.begin() + lookup_index, batch_components, batch_index);
m_shader_programs.insert(
m_shader_programs.begin() + lookup_index,
shader_programs.begin(), shader_programs.end()
);
}
auto& batch = m_batches[batch_index].first;
const auto mesh_id = batch.add(point_cloud, bounding_box, transform);
return id_type{ batch_id, mesh_id };
}
std::optional<aabb> point_cloud_batch_renderer::bounding_box(id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id.first);
if (lookup_it == m_id_lookup.end())
{
return std::nullopt;
}
const auto batch_index = lookup_it - m_id_lookup.begin();
auto& batch = m_batches[batch_index].first;
return batch.bounding_box(id.second);
}
bool point_cloud_batch_renderer::remove(const id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id.first);
if (lookup_it == m_id_lookup.end())
{
return false;
}
const auto batch_index = lookup_it - m_id_lookup.begin();
auto& batch = m_batches[batch_index].first;
// If batches can be removed the indices in m_component_lookup need to be changed.
return batch.remove(id.second);
}
template<bool Normals>
void render_point_cloud_batch(
const zgl::shader_program_handle& shader_program,
const point_cloud_batch& batch,
const glm::mat4& vp_matrix,
const glm::vec3& camera_position
) {
const auto point_clouds = batch.point_clouds();
const auto transforms = batch.transforms();
namespace uniforms = shader_program::uniforms::point_cloud;
for (std::size_t i{}; i != point_clouds.size(); ++i)
{
const auto& point_cloud = point_clouds[i];
const auto& model_matrix = transforms[i];
// TODO check order
const auto mvp_matrix = vp_matrix * model_matrix;
shader_program.set_uniform<uniforms::mvp.info>(mvp_matrix);
if constexpr (Normals)
{
shader_program.set_uniform<uniforms::model.info>(model_matrix);
shader_program.set_uniform<uniforms::camera_position.info>(camera_position);
}
point_cloud.bind();
using block_index_type = ztu::u16;
static constexpr auto block_size = static_cast<std::size_t>(
std::numeric_limits<block_index_type>::max()
);
for (GLsizei j{}; j < point_cloud.point_count; j += block_size)
{
const auto points_left = static_cast<std::size_t>(point_cloud.point_count) - j;
const auto points_in_block = std::min(points_left, block_size);
glDrawArrays(
GL_POINTS,
j,
static_cast<block_index_type>(points_in_block)
);
}
}
}
void point_cloud_batch_renderer::render(
const modes::point_cloud render_mode,
const glm::mat4& vp_matrix,
const glm::vec3& camera_position,
const lighting_setup&
) {
namespace uniforms = shader_program::uniforms::point_cloud;
const auto render_mode_index = static_cast<std::size_t>(render_mode);
glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_POINT_SMOOTH);
const auto rainbow = render_mode == modes::point_cloud::rainbow;
for (std::size_t i{}; i != m_batches.size(); ++i) {
const auto& [ batch, vertex_components ] = m_batches[i];
const auto normals = static_cast<bool>(vertex_components & components::point_cloud_vertex::flags::normal);
const auto& shader_program = m_shader_programs[i * m_render_mode_count + render_mode_index];
shader_program.bind();
if (rainbow)
{
shader_program.set_uniform<uniforms::rainbow_offset_y.info>(0.0f); // TODO fix
shader_program.set_uniform<uniforms::rainbow_scale_y.info>(0.0f); // TODO fix
}
unroll_bool_function_template(
[&]<bool Normals>() {
render_point_cloud_batch<Normals>(
shader_program,
batch,
vp_matrix,
camera_position
);
},
normals
);
}
glDisable(GL_PROGRAM_POINT_SIZE);
glDisable(GL_POINT_SMOOTH);
zgl::point_cloud_handle::unbind();
zgl::shader_program_handle::unbind();
}
}

View File

@@ -0,0 +1,147 @@
#ifndef INCLUDE_MESH_BATCH_IMPLEMENTATION
# error Never include this file directly include 'mesh_batch.hpp'
#endif
#include <algorithm>
inline mesh_batch::id_type mesh_batch::add(
const zgl::mesh_handle& mesh,
const aabb& bounding_box,
const zgl::model_matrix_handle& transform,
const zgl::material_handle& material
) {
std::size_t index;
if (material.texture)
{
// Sort by texture id if possible, so meshes the same texture are rendered consecutively.
const auto texture_it = std::ranges::upper_bound(
m_textures,
*material.texture,
[](const auto& lhs, const auto& rhs)
{
return lhs.texture_id < rhs.texture_id;
}
);
index = texture_it - m_textures.begin();
}
else
{
// TODO inserting by vao might split up texture sequence, this needs more attention
// Otherwise, sort by vao, so meshes with the same vertices are rendered consecutively.
const auto mesh_it = std::ranges::upper_bound(
m_meshes,
mesh,
[](const auto& lhs, const auto& rhs)
{
return lhs.vao_id < rhs.vao_id;
}
);
index = mesh_it - m_meshes.begin();
}
m_meshes.insert(m_meshes.begin() + index, mesh);
m_bounding_boxes.insert(m_bounding_boxes.begin() + index, bounding_box);
m_transforms.insert(m_transforms.begin() + index, transform);
if (material.texture)
{
m_textures.insert(m_textures.begin() + index, *material.texture);
}
if (material.surface_properties)
{
m_surface_properties.insert(m_surface_properties.begin() + index, *material.surface_properties);
}
if (material.alpha)
{
m_alphas.insert(m_alphas.begin() + index, *material.alpha);
}
const auto mesh_id = m_next_mesh_id++;
m_id_lookup.insert(m_id_lookup.begin() + index, mesh_id);
return mesh_id;
}
std::optional<aabb> mesh_batch::bounding_box(id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id);
if (lookup_it == m_id_lookup.end())
{
return std::nullopt;
}
const auto index = lookup_it - m_id_lookup.begin();
const auto& base_bounding_box = m_bounding_boxes[index];
const auto& transform = m_transforms[index];
return base_bounding_box.transformed(transform);
}
inline bool mesh_batch::remove(const id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id);
if (lookup_it == m_id_lookup.end()) {
return false;
}
const auto index = lookup_it - m_id_lookup.begin();
m_id_lookup.erase(m_id_lookup.begin() + index);
m_meshes.erase(m_meshes.begin() + index);
m_bounding_boxes.erase(m_bounding_boxes.begin() + index);
m_transforms.erase(m_transforms.begin() + index);
if (not m_textures.empty())
{
m_textures.erase(m_textures.begin() + index);
}
if (not m_surface_properties.empty())
{
m_surface_properties.erase(m_surface_properties.begin() + index);
}
if (not m_alphas.empty())
{
m_alphas.erase(m_alphas.begin() + index);
}
return true;
}
inline std::span<const zgl::mesh_handle> mesh_batch::meshes() const
{
return m_meshes;
}
inline std::span<const aabb> mesh_batch::bounding_boxes() const
{
return m_bounding_boxes;
}
inline std::span<const zgl::model_matrix_handle> mesh_batch::transforms() const
{
return m_transforms;
}
inline std::span<const zgl::texture_handle> mesh_batch::textures() const
{
return m_textures;
}
inline std::span<const zgl::surface_properties_handle> mesh_batch::surface_properties() const
{
return m_surface_properties;
}
inline std::span<const zgl::alpha_handle> mesh_batch::alphas() const
{
return m_alphas;
}

View File

@@ -0,0 +1,69 @@
#ifndef INCLUDE_POINT_CLOUD_BATCH_IMPLEMENTATION
# error Never include this file directly include 'point_cloud_batch.hpp'
#endif
inline point_cloud_batch::id_type point_cloud_batch::add(
const zgl::point_cloud_handle& point_cloud,
const aabb& bounding_box,
const zgl::model_matrix_handle& transform
) {
const auto new_id = m_next_id++;
m_point_clouds.push_back(point_cloud);
m_transforms.push_back(transform);
m_bounding_boxes.push_back(bounding_box);
m_id_lookup.push_back(new_id);
return new_id;
}
std::optional<aabb> point_cloud_batch::bounding_box(id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id);
if (lookup_it == m_id_lookup.end())
{
return std::nullopt;
}
const auto index = lookup_it - m_id_lookup.begin();
const auto& base_bounding_box = m_bounding_boxes[index];
const auto& transform = m_transforms[index];
return base_bounding_box.transformed(transform);
}
inline bool point_cloud_batch::remove(id_type id)
{
const auto lookup_it = std::ranges::find(m_id_lookup, id);
if (lookup_it == m_id_lookup.end())
{
return false;
}
const auto index = lookup_it - m_id_lookup.begin();
m_id_lookup.erase(m_id_lookup.begin() + index);
m_point_clouds.erase(m_point_clouds.begin() + index);
m_transforms.erase(m_transforms.begin() + index);
return true;
}
inline std::span<const zgl::point_cloud_handle> point_cloud_batch::point_clouds() const
{
return m_point_clouds;
}
inline std::span<const zgl::model_matrix_handle> point_cloud_batch::transforms() const
{
return m_transforms;
}
inline std::span<const aabb> point_cloud_batch::bounding_boxes() const
{
return m_bounding_boxes;
}

View File

@@ -0,0 +1,58 @@
#include "rendering/shader_program_lookups/mesh_lookup.hpp"
#include "util/logger.hpp" // TODO remove
#include <bitset> // TODO remove
namespace rendering::shader_program_lookups
{
void mesh_lookup::add(
const zgl::shader_program_handle& shader_program_handle
) {
m_shader_program_lookup.add(
shader_program_handle,
shader_program::attributes::mesh::all,
shader_program::uniforms::mesh::all
);
}
std::optional<zgl::shader_program_handle> mesh_lookup::find(
requirements::mesh::flags requirements
) const {
auto capability = shader_program::capabilities::mesh::type{};
auto index = std::size_t{};
auto requirement_flags = static_cast<ztu::u32>(requirements);
while (requirement_flags)
{
if (requirement_flags & 1)
{
const auto shader_requirements_index = requirements::mesh::all[index].shader_program_requirement_index;
const auto& [ attributes, uniforms ] = shader_program::capabilities::mesh::all[shader_requirements_index];
capability.attributes |= attributes;
capability.uniforms |= uniforms;
}
requirement_flags >>= 1;
++index;
}
// TODO if not textured and not colored add ucolor "for free"
ztu::logger::debug("attributes reqs: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(capability.attributes)) });
ztu::logger::debug("uniforms reqs: %", std::bitset<32>{ static_cast<unsigned long long>(static_cast<int>(capability.uniforms)) });
return m_shader_program_lookup.find(
static_cast<ztu::u32>(capability.attributes),
static_cast<ztu::u32>(capability.uniforms),
shader_program::attributes::mesh::all
);
}
void mesh_lookup::print() {
m_shader_program_lookup.print();
}
}

View File

@@ -0,0 +1,47 @@
#include "rendering/shader_program_lookups/point_cloud_lookup.hpp"
namespace rendering::shader_program_lookups
{
void point_cloud_lookup::add(
const zgl::shader_program_handle& shader_program_handle
) {
m_program_lookup.add(
shader_program_handle,
shader_program::attributes::point_cloud::all,
shader_program::uniforms::point_cloud::all
);
}
std::optional<zgl::shader_program_handle> point_cloud_lookup::find(
requirements::point_cloud::flags requirements
) const {
auto capability = shader_program::capabilities::point_cloud::type{};
auto index = std::size_t{};
auto requirement_flags = static_cast<ztu::u32>(requirements);
while (requirement_flags)
{
if (requirement_flags & 1)
{
const auto shader_requirements_index = requirements::point_cloud::all[index].shader_program_requirement_index;
const auto& [ attributes, uniforms ] = shader_program::capabilities::point_cloud::all[shader_requirements_index];
capability.attributes |= attributes;
capability.uniforms |= uniforms;
}
requirement_flags >>= 1;
++index;
}
return m_program_lookup.find(
static_cast<ztu::u32>(capability.attributes),
static_cast<ztu::u32>(capability.uniforms),
shader_program::attributes::point_cloud::all
);
}
}