1#ifndef DONUT_GRAPHICS_MESH_HPP 
    2#define DONUT_GRAPHICS_MESH_HPP 
   27    std::is_same_v<T, u32> ||   
 
   28    std::is_same_v<T, float> || 
 
   29    std::is_same_v<T, vec2> ||  
 
   30    std::is_same_v<T, vec3> ||  
 
   31    std::is_same_v<T, vec4> ||  
 
   32    std::is_same_v<T, mat2> ||  
 
   33    std::is_same_v<T, mat3> ||  
 
   34    std::is_same_v<T, mat4>;
 
   81class MeshStatePreserver {
 
   83    [[nodiscard]] MeshStatePreserver() noexcept;
 
   84    ~MeshStatePreserver();
 
   86    MeshStatePreserver(const MeshStatePreserver&) = delete;
 
   87    MeshStatePreserver(MeshStatePreserver&&) = delete;
 
   88    MeshStatePreserver& operator=(const MeshStatePreserver&) = delete;
 
   89    MeshStatePreserver& operator=(MeshStatePreserver&&) = delete;
 
   92    std::int32_t vertexArrayBinding = 0;
 
   93    std::int32_t arrayBufferBinding = 0;
 
   96void bindVertexArray(
Handle handle);
 
   97void bindArrayBuffer(
Handle handle);
 
   98void bindElementArrayBuffer(
Handle handle);
 
   99void enableVertexAttribArray(std::uint32_t index);
 
  100void vertexAttribDivisor(std::uint32_t index, std::uint32_t divisor);
 
  101void vertexAttribPointerUint(std::uint32_t index, std::
size_t count, std::
size_t stride, std::uintptr_t offset);
 
  102void vertexAttribPointerFloat(std::uint32_t index, std::
size_t count, std::
size_t stride, std::uintptr_t offset);
 
  103void bufferArrayBufferData(std::
size_t size, const 
void* data, 
MeshBufferUsage usage);
 
  104void bufferElementArrayBufferData(std::
size_t size, const 
void* data, 
MeshBufferUsage usage);
 
  106template <
bool IsInstance>
 
  107inline 
void enableVertexAttribute(std::uint32_t index) {
 
  108    enableVertexAttribArray(index);
 
  109    if constexpr (IsInstance) {
 
  110        vertexAttribDivisor(index, 1);
 
  114template <
bool IsInstance, 
typename T>
 
  115[[nodiscard]] 
inline std::uint32_t setupVertexAttribute(std::uint32_t index, std::size_t stride, std::uintptr_t offset) {
 
  116    if constexpr (std::is_same_v<T, std::uint32_t>) {
 
  117        enableVertexAttribute<IsInstance>(index);
 
  118        vertexAttribPointerUint(index++, 1, stride, offset);
 
  119    } 
else if constexpr (std::is_same_v<T, float>) {
 
  120        enableVertexAttribute<IsInstance>(index);
 
  121        vertexAttribPointerFloat(index++, 1, stride, offset);
 
  122    } 
else if constexpr (std::is_same_v<T, vec2>) {
 
  123        enableVertexAttribute<IsInstance>(index);
 
  124        vertexAttribPointerFloat(index++, 2, stride, offset);
 
  125    } 
else if constexpr (std::is_same_v<T, vec3>) {
 
  126        enableVertexAttribute<IsInstance>(index);
 
  127        vertexAttribPointerFloat(index++, 3, stride, offset);
 
  128    } 
else if constexpr (std::is_same_v<T, vec4>) {
 
  129        enableVertexAttribute<IsInstance>(index);
 
  130        vertexAttribPointerFloat(index++, 4, stride, offset);
 
  131    } 
else if constexpr (std::is_same_v<T, mat2>) {
 
  132        enableVertexAttribute<IsInstance>(index);
 
  133        vertexAttribPointerFloat(index++, 2, stride, offset);
 
  134        enableVertexAttribute<IsInstance>(index);
 
  135        vertexAttribPointerFloat(index++, 2, stride, offset + 
sizeof(
float) * 2);
 
  136    } 
else if constexpr (std::is_same_v<T, mat3>) {
 
  137        enableVertexAttribute<IsInstance>(index);
 
  138        vertexAttribPointerFloat(index++, 3, stride, offset);
 
  139        enableVertexAttribute<IsInstance>(index);
 
  140        vertexAttribPointerFloat(index++, 3, stride, offset + 
sizeof(
float) * 3);
 
  141        enableVertexAttribute<IsInstance>(index);
 
  142        vertexAttribPointerFloat(index++, 3, stride, offset + 
sizeof(
float) * 6);
 
  143    } 
else if constexpr (std::is_same_v<T, mat4>) {
 
  144        enableVertexAttribute<IsInstance>(index);
 
  145        vertexAttribPointerFloat(index++, 4, stride, offset);
 
  146        enableVertexAttribute<IsInstance>(index);
 
  147        vertexAttribPointerFloat(index++, 4, stride, offset + 
sizeof(
float) * 4);
 
  148        enableVertexAttribute<IsInstance>(index);
 
  149        vertexAttribPointerFloat(index++, 4, stride, offset + 
sizeof(
float) * 8);
 
  150        enableVertexAttribute<IsInstance>(index);
 
  151        vertexAttribPointerFloat(index++, 4, stride, offset + 
sizeof(
float) * 12);
 
  153        throw std::invalid_argument{
"Invalid vertex attribute type!"};
 
  158template <
typename Tuple>
 
  159struct is_vertex_attributes : std::false_type {};
 
  161template <
typename... Ts>
 
  162struct is_vertex_attributes<std::tuple<Ts...>> : std::bool_constant<(vertex_attribute<std::remove_cvref_t<Ts>> && ...)> {};
 
  164template <
typename Tuple>
 
  165inline constexpr bool is_vertex_attributes_v = is_vertex_attributes<Tuple>::value;
 
  176    std::is_aggregate_v<T> &&       
 
  177    std::is_standard_layout_v<T> && 
 
  178    detail::is_vertex_attributes_v<decltype(reflection::fields(std::declval<T>()))>; 
 
  192    std::is_same_v<T, NoIndex> || 
 
  193    std::is_same_v<T, u8> ||      
 
  194    std::is_same_v<T, u16> ||     
 
  195    std::is_same_v<T, u32>;
 
  209    std::is_aggregate_v<T> &&       
 
  210    std::is_standard_layout_v<T> && 
 
  211    detail::is_vertex_attributes_v<decltype(reflection::fields(std::declval<T>()))>; 
 
  225template <
typename Vertex, 
typename Index = NoIndex, 
typename Instance = NoInstance>
 
  228    static_assert(
mesh_vertex<Vertex>, 
"Mesh template parameter \"Vertex\" must be a valid vertex type.");
 
  229    static_assert(
mesh_index<Index>, 
"Mesh template parameter \"Index\" must be a valid index type.");
 
  233    static constexpr bool IS_INDEXED = !std::is_same_v<Index, NoIndex>;
 
  236    static constexpr bool IS_INSTANCED = !std::is_same_v<Instance, NoInstance>;
 
  245    Mesh(
MeshBufferUsage verticesUsage, std::span<const Vertex> vertices) 
requires(!IS_INDEXED && !IS_INSTANCED) {
 
  246        const detail::MeshStatePreserver preserver{};
 
  247        detail::bindVertexArray(vao.get());
 
  248        bufferVertexData(verticesUsage, vertices, 0);
 
 
  262        const detail::MeshStatePreserver preserver{};
 
  263        detail::bindVertexArray(vao.get());
 
  264        bufferVertexData(verticesUsage, vertices, 0);
 
  265        bufferIndexData(indicesUsage, indices);
 
 
  280        const detail::MeshStatePreserver preserver{};
 
  281        detail::bindVertexArray(vao.get());
 
  282        bufferVertexData(verticesUsage, vertices, 0);
 
  283        bufferInstanceData(instancesUsage, instances, 
static_cast<std::uint32_t
>(reflection::aggregate_size_v<Vertex>));
 
 
  300        std::span<const Instance> instances) 
requires(IS_INDEXED && IS_INSTANCED) {
 
  301        const detail::MeshStatePreserver preserver{};
 
  302        detail::bindVertexArray(vao.get());
 
  303        bufferVertexData(verticesUsage, vertices, 0);
 
  304        bufferIndexData(indicesUsage, indices);
 
  305        bufferInstanceData(instancesUsage, instances, 
static_cast<std::uint32_t
>(reflection::aggregate_size_v<Vertex>));
 
 
  318        const detail::MeshStatePreserver preserver{};
 
  319        detail::bindVertexArray(vao.get());
 
  320        detail::bindArrayBuffer(vbo.get());
 
  321        detail::bufferArrayBufferData(
sizeof(Vertex) * vertices.size(), vertices.data(), verticesUsage);
 
 
  337        const detail::MeshStatePreserver preserver{};
 
  338        detail::bindVertexArray(vao.get());
 
  339        detail::bindArrayBuffer(vbo.get());
 
  340        detail::bufferArrayBufferData(
sizeof(Vertex) * vertices.size(), vertices.data(), verticesUsage);
 
  341        detail::bindElementArrayBuffer(ebo.get());
 
  342        detail::bufferElementArrayBufferData(
sizeof(Index) * indices.size(), indices.data(), indicesUsage);
 
 
  402    void bufferVertexData(
MeshBufferUsage usage, std::span<const Vertex> vertices, std::uint32_t attributeOffset) {
 
  403        static_assert(std::is_aggregate_v<Vertex>, 
"Vertex type must be an aggregate type!");
 
  404        static_assert(std::is_standard_layout_v<Vertex>, 
"Vertex type must have standard layout!");
 
  405        detail::bindArrayBuffer(vbo.get());
 
  406        detail::bufferArrayBufferData(
sizeof(Vertex) * vertices.size(), vertices.data(), usage);
 
  407        Vertex dummyVertex{};
 
  409            const std::byte* 
const basePointer = 
reinterpret_cast<const std::byte*
>(std::addressof(dummyVertex));
 
  410            const std::byte* 
const attributePointer = 
reinterpret_cast<const std::byte*
>(std::addressof(dummyField));
 
  411            const std::uintptr_t offset = 
static_cast<std::uintptr_t
>(attributePointer - basePointer);
 
  412            attributeOffset = detail::setupVertexAttribute<false, T>(attributeOffset, 
sizeof(Vertex), offset);
 
  416    void bufferIndexData(MeshBufferUsage usage, std::span<const Index> indices) 
requires(IS_INDEXED) {
 
  417        detail::bindElementArrayBuffer(ebo.get());
 
  418        detail::bufferElementArrayBufferData(
sizeof(Index) * indices.size(), indices.data(), usage);
 
  421    void bufferInstanceData(MeshBufferUsage usage, std::span<const Instance> instances, std::uint32_t attributeOffset) 
requires(IS_INSTANCED) {
 
  422        static_assert(std::is_aggregate_v<Instance>, 
"Instance type must be an aggregate type!");
 
  423        static_assert(std::is_standard_layout_v<Instance>, 
"Instance type must have standard layout!");
 
  424        detail::bindArrayBuffer(ibo.get());
 
  425        detail::bufferArrayBufferData(
sizeof(Instance) * instances.size(), instances.data(), usage);
 
  426        Instance dummyInstance{};
 
  428            const std::byte* 
const basePointer = 
reinterpret_cast<const std::byte*
>(std::addressof(dummyInstance));
 
  429            const std::byte* 
const attributePointer = 
reinterpret_cast<const std::byte*
>(std::addressof(dummyField));
 
  430            const std::uintptr_t offset = 
static_cast<std::uintptr_t
>(attributePointer - basePointer);
 
  431            attributeOffset = detail::setupVertexAttribute<true, T>(attributeOffset, 
sizeof(Instance), offset);
 
  437    [[no_unique_address]] std::conditional_t<IS_INDEXED, Buffer, NoIndex> ebo{};
 
  438    [[no_unique_address]] std::conditional_t<IS_INSTANCED, Buffer, NoInstance> ibo{};
 
 
Generic abstraction of a GPU vertex array object and its associated buffers.
Definition Mesh.hpp:226
 
Mesh(MeshBufferUsage verticesUsage, MeshBufferUsage instancesUsage, std::span< const Vertex > vertices, std::span< const Instance > instances)
Constructor for meshes that have a vertex buffer and an instance buffer.
Definition Mesh.hpp:278
 
Handle getInstanceBuffer() const noexcept
Get an opaque handle to the GPU representation of the instance buffer.
Definition Mesh.hpp:383
 
Mesh(MeshBufferUsage verticesUsage, std::span< const Vertex > vertices)
Constructor for meshes that only have a vertex buffer.
Definition Mesh.hpp:245
 
Handle getIndexBuffer() const noexcept
Get an opaque handle to the GPU representation of the index buffer.
Definition Mesh.hpp:369
 
Handle get() const noexcept
Get an opaque handle to the GPU representation of the vertex array.
Definition Mesh.hpp:397
 
Handle getVertexBuffer() const noexcept
Get an opaque handle to the GPU representation of the vertex buffer.
Definition Mesh.hpp:355
 
Mesh(MeshBufferUsage verticesUsage, MeshBufferUsage indicesUsage, MeshBufferUsage instancesUsage, std::span< const Vertex > vertices, std::span< const Index > indices, std::span< const Instance > instances)
Constructor for meshes that have a vertex buffer, an index buffer and an instance buffer.
Definition Mesh.hpp:299
 
void setVertices(MeshBufferUsage verticesUsage, MeshBufferUsage indicesUsage, std::span< const Vertex > vertices, std::span< const Index > indices) noexcept
Set the contents of the vertex and index buffers.
Definition Mesh.hpp:336
 
void setVertices(MeshBufferUsage verticesUsage, std::span< const Vertex > vertices) noexcept
Set the contents of the vertex buffer.
Definition Mesh.hpp:317
 
Mesh(MeshBufferUsage verticesUsage, MeshBufferUsage indicesUsage, std::span< const Vertex > vertices, std::span< const Index > indices)
Constructor for meshes that have a vertex buffer and an index buffer.
Definition Mesh.hpp:261
 
Concept that checks if a type is a valid index type.
Definition Mesh.hpp:191
 
Concept that checks if a type is a valid instance type.
Definition Mesh.hpp:208
 
Concept that checks if a type is a valid vertex type.
Definition Mesh.hpp:175
 
Concept that checks if a type is a valid vertex attribute.
Definition Mesh.hpp:26
 
std::uint32_t Handle
Generic GPU resource handle.
Definition Handle.hpp:11
 
MeshBufferUsage
Hint to the graphics driver implementation regarding the intended access pattern of a particular GPU ...
Definition Mesh.hpp:44
 
@ U8
Each pixel component is an 8-bit unsigned integer.
 
MeshPrimitiveType
Specification of which kind of graphical primitive is defined by an associated sequence of vertices i...
Definition Mesh.hpp:60
 
@ TRIANGLE_STRIP
Each point, except the first two, forms a filled triangle with the previous two points.
 
@ POINTS
Individual points.
 
@ LINE_LOOP
Each point forms a line segment to the previous point, where the last point connects back to the firs...
 
@ TRIANGLES
Each consecutive triple of points forms an individual filled triangle.
 
@ LINES
Each consecutive pair of points forms an individual line segment.
 
@ LINE_STRIP
Each point, except the first, forms a line segment to the previous point.
 
MeshIndexType
Specification of which type of indices is used in the index buffer of a particular Mesh.
Definition Mesh.hpp:73
 
@ U32
Unsigned 32-bit integer.
 
@ U16
Unsigned 16-bit integer.
 
constexpr auto fields(auto &&aggregate) noexcept
Get a tuple of references to each of the fields of an aggregate.
Definition reflection.hpp:86
 
constexpr void forEach(auto &&tuple, auto fn)
Execute a function once for each element in a given tuple, sequentially.
Definition reflection.hpp:207
 
Tag type for specifying that a Mesh does not have an index buffer.
Definition Mesh.hpp:183
 
Tag type for specifying that a Mesh does not have an instance buffer.
Definition Mesh.hpp:200