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