initial commit
All checks were successful
Build (Arch Linux) / build (push) Successful in 3m10s

This commit is contained in:
2025-04-16 01:58:29 +01:00
commit a8d8b9b9ab
116 changed files with 106633 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
#pragma once
#include <glm/vec2.hpp>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <filesystem>
#include <string_view>
#include <vector>
namespace kuiper
{
namespace resource
{
struct image_error {
std::string_view message;
};
class image {
public:
image(std::uint32_t width,
std::uint32_t height,
std::uint32_t n_channels,
const std::uint8_t* data,
std::size_t len)
: m_width(width), m_height(height), m_channels(n_channels), m_data(data, data + len) {}
image() = default;
~image() = default;
image(const image& other) = default;
image& operator=(const image& other) = default;
image(image&& other) noexcept = default;
image& operator=(image&& other) noexcept = default;
static image make_blank(std::uint32_t width, std::uint32_t height, std::uint32_t n_channels) noexcept;
static std::expected<image, image_error> from_path(const std::filesystem::path& path,
std::uint8_t num_channels = 4) noexcept;
static std::expected<image, image_error> from_memory(const std::uint8_t* data,
std::size_t len,
std::uint8_t num_channels = 4) noexcept;
std::uint32_t width() const noexcept {
return m_width;
}
std::uint32_t height() const noexcept {
return m_height;
}
glm::uvec2 dimensions() const noexcept {
return {m_width, m_height};
}
std::uint32_t channels() const noexcept {
return m_channels;
}
const std::vector<std::uint8_t>& pixel_data() const noexcept {
return m_data;
}
std::vector<std::uint8_t>& pixel_data_mut() noexcept {
return m_data;
}
void resize(std::uint32_t width, std::uint32_t height) noexcept;
private:
std::uint32_t m_width {0};
std::uint32_t m_height {0};
std::uint32_t m_channels {0};
std::vector<std::uint8_t> m_data {};
};
} // namespace resource
} // namespace kuiper

View File

@@ -0,0 +1,20 @@
#pragma once
#include "graphics/opengl/texture.hpp"
#include "graphics/opengl/texture_array.hpp"
#include <glm/vec4.hpp>
namespace kuiper::resource
{
struct material {
glm::vec4 base_colour_factor {0.0f, 0.0f, 0.0f, 1.0f};
float metallic_factor {1.0f};
float roughness_factor {1.0f};
// 0: Albedo, 1: Normal, 2: Metallic-Roughness
gl::texture_array::s_ptr textures {nullptr};
};
} // namespace kuiper::resource

View File

@@ -0,0 +1,55 @@
#pragma once
#include "maths/transform.hpp"
#include "resources/primitive.hpp"
#include <glm/mat4x4.hpp>
#include <initializer_list>
#include <vector>
namespace kuiper::resource
{
class mesh {
public:
using primitive_storage = std::vector<primitive>;
using submesh_storage = std::vector<mesh>;
mesh(const glm::mat4& t)
: m_transform(t) {}
mesh(const glm::mat4& t, std::initializer_list<primitive> primitives)
: m_transform(t) {
for (const auto& p : primitives) {
m_primitives.push_back(p);
}
}
void add_primitive(const primitive& prim) {
return m_primitives.push_back(prim);
}
void add_submesh(const class mesh& mesh) {
return m_submeshes.push_back(mesh);
}
const glm::mat4& transform() const noexcept {
return m_transform;
}
const primitive_storage& primitives() const noexcept {
return m_primitives;
}
const submesh_storage& submeshes() const noexcept {
return m_submeshes;
}
private:
primitive_storage m_primitives {};
submesh_storage m_submeshes {};
glm::mat4 m_transform {};
};
} // namespace kuiper::resource

View File

@@ -0,0 +1,56 @@
#pragma once
#include "errors/errors.hpp"
#include "resources/material.hpp"
#include "resources/mesh.hpp"
#include <fastgltf/core.hpp>
#include <expected>
#include <filesystem>
#include <vector>
namespace kuiper::resource
{
class model {
public:
using mesh_storage = std::vector<mesh>;
using material_storage = std::vector<material>;
model() = default;
model(std::initializer_list<mesh> meshes) {
for (const auto& m : meshes) {
m_meshes.push_back(m);
}
}
void push_mesh(const mesh& m) {
return m_meshes.push_back(m);
}
void push_material(const material& m) {
return m_materials.push_back(m);
}
const mesh_storage& meshes() const noexcept {
return m_meshes;
}
const material_storage& materials() const noexcept {
return m_materials;
}
/// Construct a `model` from a path to a glTF file
static std::expected<model, kuiper::error> from_gltf_path(const std::filesystem::path& gltf_path);
/// Construct a `model` from a path to a glTF file, prefer this function to the above as fastgltf's `Parser` should
/// ideally be re-used (only on one thread, though)
static std::expected<model, kuiper::error> from_gltf_path(const std::filesystem::path& gltf_path,
fastgltf::Parser& gltf_parser);
private:
mesh_storage m_meshes;
material_storage m_materials;
};
} // namespace kuiper::resource

View File

@@ -0,0 +1,38 @@
#pragma once
#include <cstddef>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <cstdint>
#include <vector>
namespace kuiper
{
struct vertex {
glm::vec3 position; // (x, y, z), float
glm::vec3 normal; // (x, y, z), float
glm::vec4 tangent; // (x, y, z, w), float
glm::vec2 uv; // (x, y) float
};
enum class primitive_type : std::uint8_t {
none = 0,
triangles
};
} // namespace kuiper
namespace kuiper::resource
{
struct primitive {
primitive_type type {primitive_type::none};
std::vector<vertex> vertices {};
std::vector<std::uint32_t> indices {};
std::size_t material_idx {};
};
} // namespace kuiper::resource

View File

@@ -0,0 +1,13 @@
#pragma once
#include <filesystem>
namespace kuiper::resource
{
class index {
public:
static index from_file(const std::filesystem::path& index_path) noexcept;
};
} // namespace kuiper::resource

View File

@@ -0,0 +1,96 @@
#pragma once
#include "graphics/opengl/shader.hpp"
#include "graphics/opengl/texture.hpp"
#include "resources/material.hpp"
#include "resources/model.hpp"
#include "utils/xoshiro256plusplus.hpp"
#include <absl/container/flat_hash_map.h>
#include <concepts>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
namespace kuiper
{
using resource_id_t = std::uint32_t;
enum class resource_type : std::uint8_t {
none = 0,
texture,
shader,
model
};
struct resource_metadata {
resource_id_t id {0};
resource_type type {resource_type::none};
std::string name {};
};
class resource_manager {
public:
using metadata_map_t = absl::flat_hash_map<resource_id_t, resource_metadata>;
using texture_map_t = absl::flat_hash_map<resource_id_t, gl::texture::s_ptr>;
using shader_map_t = absl::flat_hash_map<resource_id_t, gl::shader::s_ptr>;
using model_map_t = absl::flat_hash_map<resource_id_t, resource::model>;
using material_map_t = absl::flat_hash_map<resource_id_t, resource::material>;
template<typename T>
resource_metadata add(T&& resource, std::string_view name = {}) {
const auto new_id = static_cast<resource_id_t>(m_prng.next());
resource_type type = resource_type::none;
if constexpr (std::same_as<T, resource::model>) {
type = resource_type::model;
m_models.insert({new_id, std::forward<T>(resource)});
} else {
static_assert(!"non-exhaustive if constexpr");
}
resource_metadata metadata {new_id, type, std::string(name)};
m_metadata.insert({new_id, metadata});
return metadata;
}
template<typename T>
std::optional<T> get(resource_id_t id) {
if constexpr (std::same_as<T, resource::model>) {
if (m_models.contains(id)) {
return m_models.at(id);
} else {
return std::nullopt;
}
} else {
static_assert(!"non-exhaustive if constexpr");
}
return std::nullopt;
}
std::optional<resource_metadata> import_from_path(const std::filesystem::path& path);
const metadata_map_t& metadata() const noexcept {
return m_metadata;
}
const model_map_t& models() const noexcept {
return m_models;
}
private:
random::xoshiro256pp m_prng {random::xoshiro256pp::from_random_device()};
metadata_map_t m_metadata {};
texture_map_t m_textures {};
shader_map_t m_shaders {};
model_map_t m_models {};
material_map_t m_materials {};
};
} // namespace kuiper