Program Listing for File Scene.ixx

Program Listing for File Scene.ixx#

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

module;
#include <optional>
#include <algorithm>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <memory>
#include <vector>
#include <vulkan/vulkan.hpp>

export module kataglyphis.vulkan.scene;

import kataglyphis.vulkan.obj_material;
import kataglyphis.vulkan.vertex;
import kataglyphis.vulkan.model;
import kataglyphis.vulkan.obj_loader;
import kataglyphis.vulkan.texture;
import kataglyphis.vulkan.mesh;
import kataglyphis.vulkan.frustum;
import kataglyphis.vulkan.async_model_parse;
import kataglyphis.vulkan.device;
import kataglyphis.vulkan.object_description;
import kataglyphis.vulkan.scene_config;

export namespace Kataglyphis {
class Scene
{
  public:
    Scene();

    void update_model_matrix(glm::mat4 model_matrix, uint32_t model_id);

    // The same `model_index >= model_list.size()` rule was spelled out by
    // hand in eleven places across three files: ten Scene.ixx accessors and
    // Scene.cpp's update_model_matrix, plus the mesh half repeated per-call
    // in MeshDrawRecorder.cpp's and CascadedShadowMap.cpp's per-mesh record
    // loops (four Scene calls per mesh, each re-deriving the same model and
    // mesh pointer). findModel()/findMesh() are the one definition; every
    // fallback value stays byte-identical to what it replaced - in
    // particular getMeshBounds()'s inverted box, which isVisible() treats as
    // visible, so a missing bound must never skip a draw.
    //
    // Public, not private: MeshDrawRecorder and CascadedShadowMap are
    // separate translation units and hoist their own Mesh* with these.
    [[nodiscard]] Model *findModel(uint32_t model_index) const
    {
        return model_index < model_list.size() ? model_list[static_cast<size_t>(model_index)].get() : nullptr;
    };
    [[nodiscard]] Mesh *findMesh(uint32_t model_index, uint32_t mesh_index) const
    {
        Model *model = findModel(model_index);
        return model != nullptr ? model->getMesh(static_cast<size_t>(mesh_index)) : nullptr;
    };

    std::vector<Texture> &getTextures(uint32_t model_index)
    {
        Model *model = findModel(model_index);
        if (model == nullptr) {
            static std::vector<Texture> empty;
            return empty;
        }
        return model->getTextures();
    };
    std::vector<vk::Sampler> &getTextureSampler(uint32_t model_index)
    {
        Model *model = findModel(model_index);
        if (model == nullptr) {
            static std::vector<vk::Sampler> empty;
            return empty;
        }
        return model->getTextureSamplers();
    };
    uint32_t getTextureCount(uint32_t model_index) const
    {
        Model *model = findModel(model_index);
        return model != nullptr ? model->getTextureCount() : 0;
    };
    uint32_t getModelCount() const { return static_cast<uint32_t>(model_list.size()); };
    glm::mat4 getModelMatrix(uint32_t model_index) const {
        Model *model = findModel(model_index);
        return model != nullptr ? model->getModel() : glm::mat4(1.0f);
    };
    uint32_t getMeshCount(uint32_t model_index) const
    {
        Model *model = findModel(model_index);
        return model != nullptr ? static_cast<uint32_t>(model->getMeshCount()) : 0;
    };
    // This ordering is the contract assignTextureOffsets and
    // planFlattenedTextureSlots are both indexed by; consumers must use this
    // accessor rather than re-deriving the per-model vector themselves.
    std::vector<uint32_t> getTextureCountPerModel() const
    {
        std::vector<uint32_t> counts;
        counts.reserve(model_list.size());
        for (uint32_t i = 0; i < static_cast<uint32_t>(model_list.size()); ++i) {
            counts.push_back(getTextureCount(i));
        }
        return counts;
    };
    std::vector<uint32_t> getMeshCountPerModel() const
    {
        std::vector<uint32_t> counts;
        counts.reserve(model_list.size());
        for (uint32_t i = 0; i < static_cast<uint32_t>(model_list.size()); ++i) {
            counts.push_back(getMeshCount(i));
        }
        return counts;
    };
    vk::Buffer getVertexBuffer(uint32_t model_index, uint32_t mesh_index) const
    {
        Mesh *mesh = findMesh(model_index, mesh_index);
        return mesh != nullptr ? mesh->getVertexBuffer() : vk::Buffer{};
    };
    vk::Buffer getIndexBuffer(uint32_t model_index, uint32_t mesh_index) const
    {
        Mesh *mesh = findMesh(model_index, mesh_index);
        return mesh != nullptr ? mesh->getIndexBuffer() : vk::Buffer{};
    };
    uint32_t getIndexCount(uint32_t model_index, uint32_t mesh_index) const
    {
        Mesh *mesh = findMesh(model_index, mesh_index);
        return mesh != nullptr ? mesh->getIndexCount() : 0;
    };
    bool isMeshDoubleSided(uint32_t model_index, uint32_t mesh_index) const
    {
        Mesh *mesh = findMesh(model_index, mesh_index);
        return mesh != nullptr && mesh->isDoubleSided();
    };
    const AABB &getMeshBounds(uint32_t model_index, uint32_t mesh_index) const
    {
        static const AABB unknown{ glm::vec3(1.0F), glm::vec3(-1.0F) };
        Mesh *mesh = findMesh(model_index, mesh_index);
        return mesh != nullptr ? mesh->getBounds() : unknown;
    };
    std::vector<ObjectDescription> getObjectDescriptions() const { return object_descriptions; };
    std::vector<std::shared_ptr<Model>> const &get_model_list() const { return model_list; };

    void loadModel(const std::shared_ptr<VulkanDevice> &device, vk::CommandPool commandPool);

    void beginModelLoadAsync();

    [[nodiscard]] bool isModelLoadPending() const;

    bool pollModelLoad(const std::shared_ptr<VulkanDevice> &device, vk::CommandPool commandPool);

    void cancelPendingModelLoad();

    void reloadModel(const std::shared_ptr<VulkanDevice> &device, vk::CommandPool commandPool, const std::string &modelPath);

    std::optional<uint32_t> loadAdditionalModel(const std::shared_ptr<VulkanDevice> &device,
      vk::CommandPool commandPool,
      const std::string &modelPath,
      const glm::mat4 &modelMatrix);

    std::optional<uint32_t> add_model(const std::shared_ptr<Model> &model);

    void cleanUp();
    ~Scene();

  private:
    AsyncModelParse pendingModelParse;
    bool modelLoadPending{ false };
    std::vector<ObjectDescription> object_descriptions;
    std::vector<std::shared_ptr<Model>> model_list;

};
}// namespace Kataglyphis