#pragma once #include "opengl/type_utils.hpp" #include "opengl/metadata/vertex_buffer_metadata.hpp" #include "util/specialised_lambda.hpp" #include #include #include #include #include namespace zgl::vertex_buffer_utils { namespace detail { template concept numeric_type = std::integral or std::floating_point; template void for_enabled_components( const C components, auto&& f, std::span buffers... ) { ( [&, index = std::size_t{}](const auto& buffer) { if ((components & static_cast(1 << index)) != C{}) { f(buffer, index); } ++index; }(buffers), ... ); }; } template vertex_buffer_metadata generate_metadata( const C components, std::span buffers... ) { auto meta = vertex_buffer_metadata{}; detail::for_enabled_components( components, ztu::specialised_lambda { // Visitor for scalar values [&](const std::span&, std::size_t index) { auto& component = meta.components[index]; component.type = type_utils::to_gl_type(); component.count = 1; ++meta.component_count; }, // Visitor for numbers [&](const std::span>&, std::size_t index) { auto& component = meta.components[index]; component.type = type_utils::to_gl_type(); component.count = Count; ++meta.component_count; } }, buffers... ); for (const auto& component : std::span(meta.components).subspan(0, meta.component_count)) { meta.stride += type_utils::size_of(component.type) * component.count; } return meta; } template void interlace( std::vector& vertex_buffer, const C components, std::span buffers... ) { std::array byte_offsets; auto stride = std::size_t{}; detail::for_enabled_components( components, [&]( const std::span&, std::size_t index ) { byte_offsets[index] = stride; stride += sizeof(Component); }, buffers... ); const auto vertex_count = std::min({ buffers.size()... }); const auto buffer_size = stride * vertex_count; vertex_buffer.resize(buffer_size); detail::for_enabled_components( components, [&](const std::span& buffer, std::size_t index) { const auto byte_offset = byte_offsets[index]; for (const auto& value : buffer.subspan(0, vertex_count)) { std::memcpy( &vertex_buffer[byte_offset], &value, sizeof(value) ); byte_offset += stride; } }, buffers... ); }; }