86 lines
3.3 KiB
C++
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
|