227 lines
9.4 KiB
C++
227 lines
9.4 KiB
C++
#include "Gallery_Scene3D.h"
|
|
|
|
#include "../Gallery_Capture_Json.h"
|
|
#include "../common/Observer_Json.h"
|
|
#include "../common/Pixel_Frame.h"
|
|
#include "render_3D/Render_Scene_3D.h"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace renderive::web {
|
|
template <>
|
|
struct Observer_Pfr_Adapter<renderive::render_3d::Render_Scene_3D::State> {
|
|
using Scene = renderive::render_3d::Render_Scene_3D;
|
|
using Type = adminive::Boost_Pfr_Base_Reflection_Adapter<
|
|
Scene::State, Scene::State_Fields>;
|
|
};
|
|
template <>
|
|
struct Observer_Pfr_Adapter<renderive::render_3d::Render_Scene_3D::Observer> {
|
|
using Scene = renderive::render_3d::Render_Scene_3D;
|
|
using Type = adminive::Boost_Pfr_Base_Reflection_Adapter<
|
|
Scene::Observer, Scene::Observer_Fields>;
|
|
};
|
|
namespace {
|
|
using namespace renderive::render_3d;
|
|
|
|
std::shared_ptr<Frame_Control_Strategy_Base> make_strategy(
|
|
Gallery_Frame_Mode mode) {
|
|
switch (mode) {
|
|
case Gallery_Frame_Mode::Manual:
|
|
return std::make_shared<Manual_Render_Scene_3D_Strategy>();
|
|
case Gallery_Frame_Mode::Low_Latency:
|
|
return std::make_shared<Low_Latency_Render_Scene_3D_Strategy>();
|
|
case Gallery_Frame_Mode::Playback:
|
|
return std::make_shared<Playback_Render_Scene_3D_Strategy>();
|
|
}
|
|
return {};
|
|
}
|
|
|
|
std::string_view mode_id(Gallery_Frame_Mode mode) {
|
|
switch (mode) {
|
|
case Gallery_Frame_Mode::Manual: return "manual";
|
|
case Gallery_Frame_Mode::Low_Latency: return "low_latency";
|
|
case Gallery_Frame_Mode::Playback: return "playback";
|
|
}
|
|
return "low_latency";
|
|
}
|
|
|
|
Visual_Family visual_family(std::string_view case_id) {
|
|
if (case_id == "datoviz_splat") return Visual_Family::Splat;
|
|
if (case_id == "datoviz_pixel") return Visual_Family::Pixel;
|
|
if (case_id == "datoviz_marker") return Visual_Family::Marker;
|
|
if (case_id == "datoviz_sphere") return Visual_Family::Sphere;
|
|
if (case_id == "datoviz_segment") return Visual_Family::Segment;
|
|
if (case_id == "datoviz_vector") return Visual_Family::Vector;
|
|
if (case_id == "datoviz_primitive") return Visual_Family::Primitive;
|
|
if (case_id == "datoviz_mesh") return Visual_Family::Mesh;
|
|
if (case_id == "datoviz_path") return Visual_Family::Path;
|
|
if (case_id == "datoviz_image") return Visual_Family::Image;
|
|
if (case_id == "datoviz_labels") return Visual_Family::Labels;
|
|
if (case_id == "datoviz_glyph") return Visual_Family::Glyph;
|
|
if (case_id == "datoviz_text") return Visual_Family::Text;
|
|
if (case_id == "datoviz_volume") return Visual_Family::Volume;
|
|
return Visual_Family::Point;
|
|
}
|
|
|
|
class Gallery_Scene3D final : public Gallery_Scene_Interface {
|
|
public:
|
|
Gallery_Scene3D(std::string case_id, Gallery_Frame_Mode mode,
|
|
bool automatic)
|
|
: case_id_(std::move(case_id)), mode_(mode), automatic_(automatic) {
|
|
rebuild();
|
|
}
|
|
|
|
const std::string& case_id() const noexcept override { return case_id_; }
|
|
|
|
nlohmann::json controls() const override {
|
|
return {{"resources", nlohmann::json::array()},
|
|
{"observers", nlohmann::json::array()},
|
|
{"render_plan", gallery_render_plan_json(*scene_)},
|
|
{"performance_capture", gallery_performance_capture_json(*scene_)}};
|
|
}
|
|
|
|
Gallery_Frame_Mode frame_mode() const noexcept override { return mode_; }
|
|
void reset_monitoring() override { render_count_ = 0; }
|
|
bool can_render_automatically() const noexcept override {
|
|
return automatic_ && mode_ == Gallery_Frame_Mode::Low_Latency;
|
|
}
|
|
std::uint64_t kernel_refresh_interval_ns() const override {
|
|
return scene_->observer().next_refresh_interval_ns;
|
|
}
|
|
void set_client_metrics(Gallery_Client_Performance metrics) noexcept override {
|
|
client_ = metrics;
|
|
}
|
|
adminive::Update_Result apply_patch(
|
|
std::string_view, const nlohmann::json&) override {
|
|
return {false, "no editable resource matches the requested target"};
|
|
}
|
|
void resize(int width, int height) override {
|
|
const Extent requested{static_cast<std::uint32_t>(std::max(1, width)),
|
|
static_cast<std::uint32_t>(std::max(1, height))};
|
|
if (requested.width == extent_.width && requested.height == extent_.height)
|
|
return;
|
|
extent_ = requested;
|
|
rebuild();
|
|
}
|
|
void dispatch(const Gallery_Input_Event&) override {}
|
|
|
|
Gallery_Render_Result render_latest_frame() override {
|
|
if (scene_->request_frame() != Frame_Request_Result::none)
|
|
return Gallery_Render_Result::backend_failure;
|
|
++render_count_;
|
|
return Gallery_Render_Result::none;
|
|
}
|
|
|
|
std::optional<std::string> encode_latest_pixels() override {
|
|
const auto frame = scene_->latest_frame();
|
|
if (!frame || frame->rgba8.empty()) return std::nullopt;
|
|
auto pixels = encode_rgba8_pixel_frame(
|
|
frame->rgba8.data(), frame->extent.width, frame->extent.height,
|
|
frame->extent.width * 4U, frame->sequence);
|
|
return pixels.empty() ? std::nullopt
|
|
: std::optional<std::string>(std::move(pixels));
|
|
}
|
|
|
|
void record_pixel_response(std::chrono::steady_clock::time_point,
|
|
std::chrono::steady_clock::time_point,
|
|
std::chrono::steady_clock::time_point,
|
|
std::size_t) override {}
|
|
|
|
std::string action(const Gallery_Action_Request& request,
|
|
bool& recognized) override {
|
|
recognized = true;
|
|
if (request.id == "frame_strategy_manual" ||
|
|
request.id == "frame_strategy_low_latency" ||
|
|
request.id == "frame_strategy_playback") {
|
|
const auto next = request.id == "frame_strategy_manual"
|
|
? Gallery_Frame_Mode::Manual
|
|
: request.id == "frame_strategy_playback"
|
|
? Gallery_Frame_Mode::Playback
|
|
: Gallery_Frame_Mode::Low_Latency;
|
|
const auto operation = scene_->edit_renderables(
|
|
[strategy = make_strategy(next)](
|
|
Scene_3D_Base::Renderable_Editor& editor) mutable {
|
|
editor.replace_frame_control_strategy(std::move(strategy));
|
|
});
|
|
if (operation.wait() != Scene_Edit_Error::none)
|
|
return "frame strategy replacement rejected";
|
|
mode_ = next;
|
|
return "frame strategy replaced";
|
|
}
|
|
if (request.id == "mode_cycle" || request.id == "mode_render") {
|
|
static_cast<void>(render_latest_frame());
|
|
return "frame rendered";
|
|
}
|
|
if (request.id == "capture_next_frame") {
|
|
const auto capture = scene_->capture_next_frame();
|
|
if (capture) static_cast<void>(render_latest_frame());
|
|
return capture ? "frame captured" : "capture request rejected";
|
|
}
|
|
if (request.id == "capture_frames") {
|
|
std::size_t count = 20;
|
|
if (request.argument && std::holds_alternative<double>(*request.argument))
|
|
count = static_cast<std::size_t>(std::clamp(
|
|
std::get<double>(*request.argument), 1.0, 1000.0));
|
|
const auto capture = scene_->capture_frames(count);
|
|
if (capture) static_cast<void>(render_latest_frame());
|
|
return capture ? "frame capture started" : "capture request rejected";
|
|
}
|
|
recognized = false;
|
|
return {};
|
|
}
|
|
|
|
void record_action_notice_if_empty(std::string_view) override {}
|
|
|
|
std::string telemetry_json() const override {
|
|
const auto observer = scene_->observer();
|
|
auto kernel_observer = observer_json(observer);
|
|
kernel_observer["mode"] = mode_id(mode_);
|
|
kernel_observer["event"] = "render_completed";
|
|
kernel_observer["limit"] = "none";
|
|
return nlohmann::json{
|
|
{"kernel_observer", std::move(kernel_observer)},
|
|
{"performance", {{"successful_render_count", render_count_}}},
|
|
{"client_performance", {{"transport_fps", client_.transport_fps}}},
|
|
{"performance_capture", gallery_performance_capture_json(*scene_)}}
|
|
.dump();
|
|
}
|
|
|
|
private:
|
|
void rebuild() {
|
|
std::vector<Point> points{
|
|
{{-0.55F, -0.25F, 0.0F}, {255, 80, 80, 255}, 24.0F},
|
|
{{0.0F, 0.45F, 0.0F}, {80, 255, 120, 255}, 28.0F},
|
|
{{0.55F, -0.1F, 0.0F}, {80, 140, 255, 255}, 26.0F}};
|
|
visual_ = Point_Visual::Builder{}.build(std::move(points));
|
|
visual_->set_object_name(case_id_ + " Points");
|
|
Render_Scene_3D::State state;
|
|
state.viewport = extent_;
|
|
state.visual_family = visual_family(case_id_);
|
|
scene_ = Render_Scene_3D::Builder{state}.build(
|
|
visual_, make_strategy(mode_));
|
|
static_cast<void>(scene_->request_frame());
|
|
}
|
|
|
|
std::string case_id_;
|
|
Gallery_Frame_Mode mode_;
|
|
bool automatic_{};
|
|
Extent extent_{560, 320};
|
|
std::shared_ptr<Point_Visual> visual_;
|
|
std::unique_ptr<Render_Scene_3D> scene_;
|
|
Gallery_Client_Performance client_;
|
|
std::uint64_t render_count_{};
|
|
};
|
|
} // namespace
|
|
|
|
std::unique_ptr<Gallery_Scene_Interface> make_gallery_scene_3d(
|
|
std::uint64_t, std::string case_id, Gallery_Frame_Mode mode,
|
|
bool automatic_low_latency) {
|
|
return std::make_unique<Gallery_Scene3D>(
|
|
std::move(case_id), mode, automatic_low_latency);
|
|
}
|
|
} // namespace renderive::web
|