Program Listing for File Mesh.ixx

Program Listing for File Mesh.ixx#

Return to documentation for file (Src/GraphicsEngineVulkan/scene/Mesh.ixx)

module;
#include <memory>
#include <glm/glm.hpp>
#include <vector>
#include <vulkan/vulkan.hpp>

export module kataglyphis.vulkan.mesh;

import kataglyphis.vulkan.obj_material;
import kataglyphis.vulkan.object_description;
import kataglyphis.vulkan.vertex;
import kataglyphis.vulkan.device;
import kataglyphis.vulkan.buffer;
import kataglyphis.vulkan.buffer_manager;
import kataglyphis.vulkan.frustum;

export namespace Kataglyphis {
// this a simple Mesh without mesh generation
class Mesh
{
  public:
    Mesh(const std::shared_ptr<VulkanDevice> &device,
      vk::CommandPool transfer_command_pool,
      const std::vector<Vertex> &vertices,
      const std::vector<uint32_t> &indices,
      const std::vector<unsigned int> &materialIndex,
      const std::vector<ObjMaterial> &materials);

    Mesh();
    Mesh(const Mesh &) = delete;
    Mesh &operator=(const Mesh &) = delete;
    Mesh(Mesh &&other) noexcept = default;
    Mesh &operator=(Mesh &&other) noexcept = default;

    void cleanUp();

    ObjectDescription &getObjectDescription() { return object_description; };
    uint32_t getVertexCount() const { return vertex_count; };
    uint32_t getIndexCount() const { return index_count; };
    vk::Buffer &getVertexBuffer() { return vertexBuffer.getBuffer(); };
    vk::Buffer &getIndexBuffer() { return indexBuffer.getBuffer(); };

    const AABB &getBounds() const { return bounds; };

    void setDoubleSided(bool value) { double_sided = value; };
    bool isDoubleSided() const { return double_sided; };

    bool hasMaskedMaterial() const { return has_masked_material; };

    ~Mesh();

  private:
    AABB bounds{ glm::vec3(1.0F), glm::vec3(-1.0F) };
    VulkanBufferManager vulkanBufferManager;

    static constexpr uint64_t INVALID_ADDR = ~uint64_t(0);
    ObjectDescription object_description{ INVALID_ADDR,
        INVALID_ADDR,
        INVALID_ADDR,
        INVALID_ADDR };

    VulkanBuffer vertexBuffer;
    VulkanBuffer indexBuffer;
    VulkanBuffer materialIdsBuffer;
    VulkanBuffer materialsBuffer;

    static constexpr uint32_t INVALID_COUNT = ~uint32_t(0);
    uint32_t vertex_count{ INVALID_COUNT };
    uint32_t index_count{ INVALID_COUNT };

    // glTF material.doubleSided; see setDoubleSided.
    bool double_sided{ false };

    // See hasMaskedMaterial().
    bool has_masked_material{ false };

    std::shared_ptr<VulkanDevice>device{ nullptr };

    void createVertexBuffer(vk::CommandPool transfer_command_pool, const std::vector<Vertex> &vertices);

    void createIndexBuffer(vk::CommandPool transfer_command_pool, const std::vector<uint32_t> &indices);

    void createMaterialIDBuffer(vk::CommandPool transfer_command_pool,
      const std::vector<unsigned int> &materialIndex);

    void createMaterialBuffer(vk::CommandPool transfer_command_pool,
      const std::vector<ObjMaterial> &materials);

    // Shared body of the four create*Buffer uploads: a device-local buffer,
    // eTransferDst plus the caller's `baseUsage` bit(s), and - when the device
    // supports it - the buffer-device-address / ray-tracing-input usage and the
    // matching allocate flag, so the buffer's address can be fetched afterwards.
    // Each create*Buffer differs only in its target buffer and base usage bit,
    // so they all funnel through here.
    template<typename T>
    bool uploadDeviceLocalBuffer(vk::CommandPool transfer_command_pool,
      VulkanBuffer &targetBuffer,
      vk::BufferUsageFlags baseUsage,
      const std::vector<T> &data);
};

template<typename T>
inline bool Mesh::uploadDeviceLocalBuffer(vk::CommandPool transfer_command_pool,
  VulkanBuffer &targetBuffer,
  vk::BufferUsageFlags baseUsage,
  const std::vector<T> &data)
{
    vk::BufferUsageFlags usage_flags = {};
    usage_flags |= vk::BufferUsageFlagBits::eTransferDst;
    usage_flags |= baseUsage;
    vk::MemoryPropertyFlags const memory_property_flags = vk::MemoryPropertyFlagBits::eDeviceLocal;
    vk::MemoryAllocateFlags memory_allocate_flags = {};

    if (device->supportsBufferDeviceAddress()) {
        usage_flags |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
        if (device->supportsHardwareAcceleratedRRT()) {
            usage_flags |= vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR;
        }
        memory_allocate_flags |= vk::MemoryAllocateFlagBits::eDeviceAddress;
    }

    return vulkanBufferManager.createBufferAndUploadVectorOnDevice(
      device, transfer_command_pool, targetBuffer, usage_flags, memory_property_flags, data, memory_allocate_flags);
}
}// namespace Kataglyphis