Files
Aethera/kernel/kernel/include/function/scene/Scene.cpp
T
2026-09-02 11:09:06 +08:00

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