74 lines
3.5 KiB
C++
74 lines
3.5 KiB
C++
#include "Scene.hpp"
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
namespace aethera {
|
|
namespace detail {
|
|
struct Scene_Frame {};
|
|
}
|
|
Scene::Private::Private() = default;
|
|
proxy<frame_policy::Frame> Scene::Private::create_frame() {
|
|
return pro::make_proxy<frame_policy::Frame, detail::Scene_Frame>();
|
|
}
|
|
proxy<scene::Task_Graph>& Scene::Private::taskflow() {
|
|
return graph;
|
|
}
|
|
auto Scene::Private::create_taskflow() -> std::expected<proxy<scene::Task_Graph>, Create_Taskflow_Result> {
|
|
auto result = scene::make_task_graph("scene.renderables");
|
|
std::unordered_map<std::uint64_t, proxy<scene::Task_Node>> nodes;
|
|
auto& renderables = get<Scene_Renderable_Dag>().internal.use();
|
|
std::optional<Create_Taskflow_Result> error;
|
|
renderables.for_each_topological([&](Dag_Node_Id id, proxy<scene::Renderable>& renderable) {
|
|
if (error) return;
|
|
auto taskflow = renderable->taskflow();
|
|
auto component = taskflow->component();
|
|
auto composed = result->compose("renderable." + std::to_string(id.value), component);
|
|
if (!composed) {
|
|
switch (composed.error()) {
|
|
case scene::Compose_Task_Graph_Result::component_unavailable: error = Create_Taskflow_Result::component_unavailable;
|
|
break;
|
|
case scene::Compose_Task_Graph_Result::dependency_cycle: error = Create_Taskflow_Result::dependency_cycle;
|
|
break;
|
|
case scene::Compose_Task_Graph_Result::already_composed: error = Create_Taskflow_Result::already_composed;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
nodes.emplace(id.value, std::move(*composed));
|
|
});
|
|
if (error) return std::unexpected(*error);
|
|
renderables.for_each_dependency([&](Dag_Node_Id target, Dag_Node_Id source) {
|
|
if (result->precede(nodes.at(source.value), nodes.at(target.value)) != scene::Precede_Task_Graph_Result::preceded) error = Create_Taskflow_Result::dependency_unavailable;
|
|
});
|
|
if (error) return std::unexpected(*error);
|
|
return result;
|
|
}
|
|
auto Scene::Private::advance() -> std::expected<void, Create_Taskflow_Result> {
|
|
auto& renderables = get<Scene_Renderable_Dag>();
|
|
renderables.internal.advance();
|
|
renderables.internal.use().for_each_topological([](Dag_Node_Id, proxy<scene::Renderable>& renderable) {
|
|
renderable->advance();
|
|
});
|
|
auto next_graph = create_taskflow();
|
|
if (!next_graph) return std::unexpected(next_graph.error());
|
|
graph = std::move(*next_graph);
|
|
return {};
|
|
}
|
|
frame_policy::Render_Scene_Result Scene::Private::render(proxy<frame_policy::Frame>& frame, frame_policy::Render_Completion completion) {
|
|
if (!frame) return frame_policy::Render_Scene_Result::frame_missing;
|
|
if (!completion) return frame_policy::Render_Scene_Result::completion_missing;
|
|
if (!advance()) return frame_policy::Render_Scene_Result::task_graph_invalid;
|
|
const auto result = graph->run([frame = std::ref(frame), completion = std::move(completion)](std::exception_ptr failure) mutable {
|
|
completion(frame.get(), std::move(failure));
|
|
});
|
|
switch (result) {
|
|
case scene::Run_Task_Graph_Result::submitted: return frame_policy::Render_Scene_Result::submitted;
|
|
case scene::Run_Task_Graph_Result::runtime_not_initialized: return frame_policy::Render_Scene_Result::runtime_not_initialized;
|
|
case scene::Run_Task_Graph_Result::completion_missing: return frame_policy::Render_Scene_Result::completion_missing;
|
|
}
|
|
std::terminate();
|
|
}
|
|
Scene::Scene() = default;
|
|
Scene::~Scene() noexcept = default;
|
|
} // namespace aethera
|