Program Listing for File MeshDrawRecorder.ixx

Program Listing for File MeshDrawRecorder.ixx#

Return to documentation for file (Src/GraphicsEngineVulkan/renderer/MeshDrawRecorder.ixx)

module;
#include <optional>
#include <cstdint>
#include <glm/glm.hpp>
#include <vulkan/vulkan.hpp>

#include "renderer/pushConstants/PushConstantRasterizer.hpp"

export module kataglyphis.vulkan.mesh_draw_recorder;

import kataglyphis.vulkan.scene;
import kataglyphis.vulkan.frustum;
import kataglyphis.vulkan.mesh;

export namespace Kataglyphis::VulkanRendererInternals {

struct MeshDrawStats
{
    unsigned int drawn;
    unsigned int considered;
};

template<typename PerModelSetup, typename CullPredicate, typename PerMeshSetup>
MeshDrawStats walkSceneMeshes(vk::CommandBuffer commandBuffer,
  Kataglyphis::Scene *scene,
  PerModelSetup &&onModel,
  CullPredicate &&shouldCull,
  PerMeshSetup &&onMesh)
{
    MeshDrawStats stats{ 0, 0 };

    // object descriptions are flattened one-per-mesh across all models
    // (Scene::add_model), so objectIndex is the running FLAT mesh index, not
    // the model index. It advances for every mesh - culled ones included -
    // to stay aligned with that buffer.
    uint32_t flat_mesh_index = 0;
    for (uint32_t m = 0; m < scene->getModelCount(); m++) {
        const glm::mat4 model_matrix = scene->getModelMatrix(m);
        onModel(model_matrix);

        for (unsigned int k = 0; k < scene->getMeshCount(m); k++) {
            const uint32_t object_index = flat_mesh_index++;
            ++stats.considered;

            // Unreachable with a null mesh: m/k come from getModelCount()/
            // getMeshCount(m), so findMesh() always resolves here. Kept as a
            // fallback rather than an assert so behaviour matches the former
            // per-accessor calls byte-for-byte.
            Mesh *mesh = scene->findMesh(m, k);
            static const AABB unknownBounds{ glm::vec3(1.0F), glm::vec3(-1.0F) };
            const AABB &meshBounds = mesh != nullptr ? mesh->getBounds() : unknownBounds;

            if (shouldCull(transformAABB(model_matrix, meshBounds))) { continue; }

            onMesh(model_matrix, object_index, mesh);

            const vk::Buffer vertex_buffer = mesh != nullptr ? mesh->getVertexBuffer() : vk::Buffer{};
            const vk::DeviceSize offset = 0;
            commandBuffer.bindVertexBuffers(0, 1, &vertex_buffer, &offset);

            commandBuffer.bindIndexBuffer(
              mesh != nullptr ? mesh->getIndexBuffer() : vk::Buffer{}, 0, vk::IndexType::eUint32);

            commandBuffer.drawIndexed(mesh != nullptr ? mesh->getIndexCount() : 0, 1, 0, 0, 0);
            ++stats.drawn;
        }
    }

    return stats;
}

MeshDrawStats recordSceneMeshDraws(vk::CommandBuffer commandBuffer,
  vk::PipelineLayout pipelineLayout,
  vk::ShaderStageFlags pushConstantStages,
  Kataglyphis::Scene *scene,
  const std::optional<FrustumPlanes> &cameraFrustum,
  PushConstantRasterizer &pushConstant);

}// namespace Kataglyphis::VulkanRendererInternals