Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.2 #77

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

v0.2 #77

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_DEBUG_POSTFIX "-d")

set(${target_prefix}_version 0.1.0)
set(${target_prefix}_version 0.2.0)

project(${target_prefix}-lib VERSION ${${target_prefix}_version})

Expand Down
12 changes: 8 additions & 4 deletions lib/engine/src/editor/reflector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,20 @@ bool Reflector::operator()(char const* label, glm::quat& out_quat) const {
auto euler = to_degree(glm::eulerAngles(out_quat));
float deg[3] = {euler.x, euler.y, euler.z};
auto const org = euler;
bool ret = false;
if (drag_float(label, deg, 0.5f, -180.0f, 180.0f, ImGuiSliderFlags_NoInput)) {
euler = {deg[0], deg[1], deg[2]};
if (auto const diff = org.x - euler.x; std::abs(diff) > 0.0f) { out_quat = glm::rotate(out_quat, glm::radians(diff), right_v); }
if (auto const diff = org.y - euler.y; std::abs(diff) > 0.0f) { out_quat = glm::rotate(out_quat, glm::radians(diff), up_v); }
if (auto const diff = org.z - euler.z; std::abs(diff) > 0.0f) { out_quat = glm::rotate(out_quat, glm::radians(diff), front_v); }
return true;
ret = true;
}
return false;
ImGui::SameLine();
if (ImGui::SmallButton("Reset")) {
out_quat = quat_identity_v;
ret = true;
}
return ret;
}

bool Reflector::operator()(char const* label, AsRgb out_rgb) const {
Expand Down Expand Up @@ -101,8 +107,6 @@ bool Reflector::operator()(Transform& out_transform, Bool& out_unified_scaling,
if (ret((*this)("Position", vec3, 0.01f))) { out_transform.set_position(vec3); }
auto quat = out_transform.orientation();
if (ret((*this)("Orientation", quat))) { out_transform.set_orientation(quat); }
ImGui::SameLine();
if (ImGui::SmallButton("Reset")) { out_transform.set_orientation(quat_identity_v); }
vec3 = out_transform.scale();
if (out_unified_scaling) {
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.01f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
Expand Down
4 changes: 2 additions & 2 deletions lib/engine/src/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@ std::optional<Skybox::Data> load_skybox_data(char const* path, AtomicLoadStatus&

for (auto [face, image] : zip_ranges(faces_v, images)) { image = load_image(json[face].as_string()); }

if (!std::all_of(std::begin(images), std::end(images), [](MaybeFuture<Image> const& i) { return i.active(); })) {
if (!std::all_of(std::begin(images), std::end(images), [](StoredFuture<Image> const& i) { return i.active(); })) {
// TODO: error
return {};
}

auto ret = Skybox::Data{};
for (auto [in, out] : zip_ranges(images, ret.images)) { out = in.get(); }
for (auto [in, out] : zip_ranges(images, ret.images)) { out = std::move(in.get()); }
return ret;
}

Expand Down
6 changes: 3 additions & 3 deletions lib/engine/src/scene_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct DirLightSSBO {

static DirLightSSBO make(DirLight const& light) {
return {
.direction = light.direction.value(),
.direction = glm::normalize(light.direction * front_v),
.diffuse = light.rgb.to_vec4(),
};
}
Expand Down Expand Up @@ -147,8 +147,8 @@ void SceneRenderer::render(Renderer& renderer, vk::CommandBuffer cb, Node const&
update_view(pipeline);
material.write_sets(pipeline, store);

if (mesh_primitive.has_joints()) {
auto& set3 = pipeline.next_set(3);
if (auto const joints_set = mesh_primitive.joints_set()) {
auto& set3 = pipeline.next_set(*joints_set);
set3.update(0, make_joint_mats(resources.skins[*node.find<Skin>()], parent));
pipeline.bind(set3);
draw(cb, mesh_primitive, {});
Expand Down
Binary file modified lib/ext/src.zip
Binary file not shown.
6 changes: 3 additions & 3 deletions lib/scene/include/facade/scene/gltf_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ struct AtomicLoadStatus {
};

template <typename T>
struct LoadFuture : MaybeFuture<T> {
struct LoadFuture : StoredFuture<T> {
LoadFuture() = default;

template <typename F>
LoadFuture(ThreadPool& pool, std::atomic<std::size_t>& post_increment, F func)
: MaybeFuture<T>(pool, [&post_increment, f = std::move(func)] {
: StoredFuture<T>(pool, [&post_increment, f = std::move(func)] {
auto ret = f();
++post_increment;
return ret;
}) {}

template <typename F>
LoadFuture(std::atomic<std::size_t>& post_increment, F func) : MaybeFuture<T>(std::move(func)) {
LoadFuture(std::atomic<std::size_t>& post_increment, F func) : StoredFuture<T>(std::move(func)) {
++post_increment;
}
};
Expand Down
3 changes: 2 additions & 1 deletion lib/scene/include/facade/scene/lights.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <facade/util/flex_array.hpp>
#include <facade/util/nvec3.hpp>
#include <facade/util/rgb.hpp>
#include <glm/gtx/quaternion.hpp>

namespace facade {
///
Expand All @@ -11,7 +12,7 @@ struct DirLight {
///
/// \brief Direction.
///
nvec3 direction{-front_v};
glm::quat direction{glm::angleAxis(glm::radians(180.0f), up_v)};
///
/// \brief Colour and intensity.
///
Expand Down
14 changes: 8 additions & 6 deletions lib/scene/include/facade/scene/scene.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ class Scene {
///
Texture make_texture(Image::View image) const;

///
/// \brief Update animations and corresponding nodes.
/// \param dt Duration to advance simulation by (time since last call to tick)
///
void tick(float dt);

///
/// \brief Obtain a mutable reference to the scene's resources.
/// \returns Mutable reference to SceneResources
Expand All @@ -211,12 +217,6 @@ class Scene {
///
RenderMode render_mode{};

///
/// \brief Update animations and corresponding nodes.
/// \param dt Duration to advance simulation by (time since last call to tick)
///
void tick(float dt);

private:
struct TreeBuilder;

Expand All @@ -241,6 +241,8 @@ class Scene {

Node make_camera_node(Id<Camera> id) const;
void add_default_camera();
void add_default_camera(TreeImpl& out, Id<Camera> id);
void add_default_light();
bool load_tree(Id<Tree> id);
Id<Mesh> add_unchecked(Mesh mesh);

Expand Down
33 changes: 20 additions & 13 deletions lib/scene/src/gltf_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,10 @@ auto make_load_future(ThreadPool* pool, std::atomic<std::size_t>& out_done, F fu
}

template <typename T>
std::vector<T> from_maybe_futures(std::vector<MaybeFuture<T>>&& futures) {
std::vector<T> from_stored(std::vector<StoredFuture<T>>&& futures) {
auto ret = std::vector<T>{};
ret.reserve(futures.size());
for (auto& future : futures) { ret.push_back(future.get()); }
for (auto& future : futures) { ret.push_back(std::move(future.get())); }
return ret;
}
} // namespace
Expand All @@ -328,9 +328,17 @@ bool Scene::GltfLoader::operator()(dj::Json const& json, DataProvider const& pro
m_status.total = 1 + meta.images + meta.textures + meta.primitives + 1;
m_status.stage = LoadStage::eParsingJson;

auto get_bytes = [&provider](std::string_view uri) {
auto loaded_bytes = std::unordered_map<std::string, ByteBuffer>{};
auto loaded_mutex = std::mutex{};
auto get_bytes = [&](std::string_view uri) {
auto str = std::string{uri};
auto lock = std::unique_lock{loaded_mutex};
if (auto it = loaded_bytes.find(str); it != loaded_bytes.end()) { return it->second.span(); }
lock.unlock();
auto ret = provider.load(uri);
return gltf2cpp::ByteArray{std::move(ret.bytes), ret.size};
lock.lock();
auto [it, _] = loaded_bytes.insert_or_assign(str, std::move(ret));
return it->second.span();
};

auto root = parser.parse(get_bytes);
Expand All @@ -341,11 +349,11 @@ bool Scene::GltfLoader::operator()(dj::Json const& json, DataProvider const& pro
m_status.stage = LoadStage::eUploadingResources;
m_scene.m_storage = {};

auto image_futures = std::vector<MaybeFuture<Image>>{};
image_futures.reserve(root.images.size());
auto images = std::vector<StoredFuture<Image>>{};
images.reserve(root.images.size());
for (auto& image : root.images) {
assert(!image.bytes.empty());
image_futures.push_back(make_load_future(thread_pool, m_status.done, [i = std::move(image)] { return Image{i.bytes.span(), std::move(i.name)}; }));
images.push_back(make_load_future(thread_pool, m_status.done, [i = std::move(image)] { return Image{i.bytes.span(), std::move(i.name)}; }));
}

for (auto const& sampler : root.samplers) { m_scene.add(to_sampler_info(sampler)); }
Expand All @@ -354,19 +362,18 @@ bool Scene::GltfLoader::operator()(dj::Json const& json, DataProvider const& pro
return m_scene.m_storage.resources.samplers[*sampler_id].sampler();
};

auto textures = std::vector<MaybeFuture<Texture>>{};
auto textures = std::vector<StoredFuture<Texture>>{};
textures.reserve(root.textures.size());
auto const images = from_maybe_futures(std::move(image_futures));
for (auto& texture : root.textures) {
textures.push_back(make_load_future(thread_pool, m_status.done, [texture = std::move(texture), &images, &get_sampler, this] {
bool const mip_mapped = !texture.linear;
auto const colour_space = texture.linear ? ColourSpace::eLinear : ColourSpace::eSrgb;
auto const tci = Texture::CreateInfo{.name = std::move(texture.name), .mip_mapped = mip_mapped, .colour_space = colour_space};
return Texture{m_scene.m_gfx, get_sampler(texture.sampler), images[texture.source], tci};
return Texture{m_scene.m_gfx, get_sampler(texture.sampler), images[texture.source].get(), tci};
}));
}

auto mesh_primitives = std::vector<MaybeFuture<MeshPrimitive>>{};
auto mesh_primitives = std::vector<StoredFuture<MeshPrimitive>>{};
auto mesh_layout = to_mesh_layout(root);
mesh_primitives.reserve(mesh_layout.primitives.size());
for (auto& data : mesh_layout.data) {
Expand All @@ -384,8 +391,8 @@ bool Scene::GltfLoader::operator()(dj::Json const& json, DataProvider const& pro

m_scene.m_storage.resources.nodes.m_array = to_nodes(root.nodes);

m_scene.replace(from_maybe_futures(std::move(textures)));
m_scene.replace(from_maybe_futures(std::move(mesh_primitives)));
m_scene.replace(from_stored(std::move(textures)));
m_scene.replace(from_stored(std::move(mesh_primitives)));

m_status.stage = LoadStage::eBuildingScenes;
if (root.cameras.empty()) {
Expand Down
49 changes: 25 additions & 24 deletions lib/scene/src/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,20 @@ struct Img1x1 {
struct Scene::TreeBuilder {
Scene& out_scene;

bool set_camera(TreeImpl& out_tree, Id<Node> id, std::span<Node const> nodes) const {
void add_cameras(TreeImpl& out_tree, Id<Node> id, std::span<Node const> nodes) const {
auto& node = nodes[id];
if (auto cam = node.find<Camera>()) {
out_tree.camera = id;
return true;
}
for (auto const child : node.children) {
if (set_camera(out_tree, child, nodes)) { return true; }
}
return false;
if (auto cam = node.find<Camera>()) { out_tree.cameras.push_back(id); }
for (auto const child : node.children) { add_cameras(out_tree, child, nodes); }
}

void set_camera(TreeImpl& out_tree, std::span<Node const> nodes) const {
for (auto const& id : out_tree.roots) {
if (set_camera(out_tree, id, nodes)) { return; }
for (auto const& id : out_tree.roots) { add_cameras(out_tree, id, nodes); }
if (!out_tree.cameras.empty()) {
out_tree.camera = out_tree.cameras.front();
return;
}
auto node = Node{.name = "camera"};
node.attach<Camera>(0);
auto const id = out_scene.m_storage.resources.nodes.size();
out_scene.m_storage.resources.nodes.m_array.push_back(std::move(node));
out_tree.roots.push_back(id);
out_tree.cameras.push_back(id);
out_tree.camera = out_tree.cameras.front();
assert(!out_scene.m_storage.resources.cameras.empty());
out_scene.add_default_camera(out_tree, 0);
}

TreeImpl operator()(Id<Tree> id) {
Expand All @@ -67,7 +58,10 @@ struct Scene::TreeBuilder {
}
};

Scene::Scene(Gfx const& gfx) : m_gfx(gfx), m_sampler(gfx) { add_default_camera(); }
Scene::Scene(Gfx const& gfx) : m_gfx(gfx), m_sampler(gfx) {
add_default_camera();
add_default_light();
}

Id<Camera> Scene::add(Camera camera) {
auto const id = m_storage.resources.cameras.size();
Expand Down Expand Up @@ -183,11 +177,18 @@ Node Scene::make_camera_node(Id<Camera> id) const {
return node;
}

void Scene::add_default_camera() {
m_tree.cameras.push_back(m_storage.resources.nodes.size());
m_tree.roots.push_back(m_storage.resources.nodes.size());
m_storage.resources.nodes.m_array.push_back(make_camera_node(add(Camera{.name = "default"})));
m_tree.camera = m_tree.cameras.front();
void Scene::add_default_camera(TreeImpl& out, Id<Camera> id) {
auto const node = add(make_camera_node(id));
out.roots.push_back(node);
out.cameras.push_back(node);
out.camera = out.cameras.front();
}

void Scene::add_default_camera() { add_default_camera(m_tree, add(Camera{.name = "default"})); }

void Scene::add_default_light() {
static auto const dir_light_orn = [] { return glm::angleAxis(glm::radians(180.0f + 45.0f), up_v) * glm::angleAxis(glm::radians(45.0f), right_v); }();
lights.dir_lights.insert(DirLight{.direction = dir_light_orn, .rgb = {.intensity = 5.0f}});
}

bool Scene::load_tree(Id<Tree> id) {
Expand Down
8 changes: 6 additions & 2 deletions lib/util/include/facade/util/rgb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,19 @@ struct Rgb {
};
}

///
/// \brief Obtain only the normalzed tint (no HDR).
///
constexpr glm::vec4 to_tint(float alpha) const { return glm::vec4{to_f32(channels.x), to_f32(channels.y), to_f32(channels.z), alpha}; }
///
/// \brief Convert instance to 3 channel normalized output.
/// \returns 3 normalized floats
///
constexpr glm::vec3 to_vec3() const { return intensity * glm::vec3{to_f32(channels.x), to_f32(channels.y), to_f32(channels.z)}; }
constexpr glm::vec3 to_vec3() const { return to_vec4(1.0f); }
///
/// \brief Convert instance to 4 channel normalized output.
/// \returns 4 normalized floats
///
constexpr glm::vec4 to_vec4(float alpha = 1.0f) const { return {to_vec3(), alpha}; }
constexpr glm::vec4 to_vec4(float alpha = 1.0f) const { return intensity * to_tint(alpha); }
};
} // namespace facade
17 changes: 10 additions & 7 deletions lib/util/include/facade/util/thread_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <future>
#include <optional>
#include <thread>
#include <utility>
#include <vector>

namespace facade {
Expand Down Expand Up @@ -63,26 +64,28 @@ class ThreadPool {
};

template <typename T>
struct MaybeFuture {
std::future<T> future{};
struct StoredFuture {
std::shared_future<T> future{};
std::optional<T> t{};

MaybeFuture() = default;
StoredFuture() = default;

template <typename F>
requires(std::same_as<std::invoke_result_t<F>, T>)
MaybeFuture(ThreadPool& pool, F func) : future(pool.enqueue([f = std::move(func)] { return f(); })) {}
StoredFuture(ThreadPool& pool, F func) : future(pool.enqueue([f = std::move(func)] { return f(); }).share()) {}

template <typename F>
requires(std::same_as<std::invoke_result_t<F>, T>)
explicit MaybeFuture(F func) : t(func()) {}
explicit StoredFuture(F func) : t(func()) {}

bool active() const { return future.valid() || t.has_value(); }

T get() {
T const& get() const {
assert(active());
if (future.valid()) { return future.get(); }
return std::move(*t);
return *t;
}

T& get() { return const_cast<T&>(std::as_const(*this).get()); }
};
} // namespace facade
2 changes: 2 additions & 0 deletions lib/vk/include/facade/vk/mesh_primitive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <facade/vk/gfx.hpp>
#include <facade/vk/vertex_layout.hpp>
#include <glm/vec4.hpp>
#include <optional>

namespace facade {
struct MeshJoints {
Expand All @@ -27,6 +28,7 @@ class MeshPrimitive {
Info info() const;
VertexLayout const& vertex_layout() const { return m_vlayout; }
bool has_joints() const { return m_jwbo.get().get().size > 0; }
std::optional<std::uint32_t> joints_set() const { return m_jwbo.get().get().size > 0 ? std::optional<std::uint32_t>{3} : std::nullopt; }
std::uint32_t instance_binding() const { return m_instance_binding; }

void draw(vk::CommandBuffer cb, std::uint32_t instances = 1u) const;
Expand Down
Loading