Files
Renderive/web_server/app/Web_Plot_Session.cpp
T
2026-08-18 12:15:41 +08:00

86 lines
3.3 KiB
C++

#include "Web_Plot_Session.h"
#include "Pixel_Frame.h"
#include "render_2D/scene/Render_Scene_2D.h"
#include <renderive/error/Error_Policy.hpp>
#include <memory>
#include <stdexcept>
#include <type_traits>
namespace renderive::web {
struct Web_Plot_Session::Impl {
Size viewport{960, 600};
std::uint64_t sequence{};
std::unique_ptr<Render_Scene_2D> scene;
Impl() { rebuild(); }
void rebuild() {
auto built_scene = Render_Scene_2D::Builder(
std::make_shared<Low_Latency_Render_Scene_2D_Strategy>())
.set<&Render_Scene_2D::Properties::viewport>(viewport)
.build();
if (!built_scene)
::renderive::error::unexpected<std::logic_error>(
"web plot scene topology validation failed");
scene = std::move(*built_scene);
scene->activate_view();
}
std::optional<Web_Response> encode_frame() {
std::string pixels;
scene->with_frame([&](Image_View image) {
pixels = encode_pixel_frame(image, ++sequence);
});
if (pixels.empty()) return std::nullopt;
return Web_Response{Web_Response_Type::Pixels, std::move(pixels)};
}
std::optional<Web_Response> handle(const Web_Event& event) {
return std::visit([this](const auto& value) -> std::optional<Web_Response> {
using T = std::decay_t<decltype(value)>;
if constexpr (std::same_as<T, Frame_Request>) {
const auto result = scene->render_frame();
if (!result || scene->wait_for_render() != Scene_Render_Result::none) return std::nullopt;
return encode_frame();
} else if constexpr (std::same_as<T, Viewport_Resize>) {
viewport = value.size;
rebuild();
} else if constexpr (std::derived_from<T, Event>) {
scene->dispatch_event(value);
}
return std::nullopt;
}, event);
}
void async_handle(const Web_Event& event, Web_Response_Completion completion) {
if (!std::holds_alternative<Frame_Request>(event)) {
completion({handle(event), {}});
return;
}
const auto result = scene->render_frame(
[this, completion](Scene_Render_Result render_result, std::exception_ptr exception) mutable {
if (exception) {
completion({{}, std::move(exception)});
return;
}
if (render_result != Scene_Render_Result::none) {
completion({});
return;
}
try {
completion({encode_frame(), {}});
}
catch (...) {
completion({{}, std::current_exception()});
}
});
if (!result || *result != Plot_Render_Status::rendered) completion({});
}
};
Web_Plot_Session::Web_Plot_Session() : impl_(std::make_unique<Impl>()) {}
Web_Plot_Session::~Web_Plot_Session() = default;
std::optional<Web_Response> Web_Plot_Session::handle(const Web_Event& event) {
return impl_->handle(event);
}
void Web_Plot_Session::async_handle(const Web_Event& event, Web_Response_Completion completion) {
impl_->async_handle(event, std::move(completion));
}
} // namespace renderive::web