#include "Gallery_Plots.hpp" #include "Renderable_Adapter.hpp" #include #include #include #include #include #include #include namespace aethera::web { namespace { using namespace render_3d; using Scene_3D = Impl; template class Visual_Scene_View final : public Plot::Scene_View { public: Visual_Scene_View(Scene_3D& scene, std::unique_ptr visual, std::string label) : visual_(std::move(visual)) { using Definition = typename Visual_Object::Attached_Object; using Prop = typename Definition::Prop; using State = typename Definition::State; using Scene_Adapter = detail::Renderable_Adapter, detail::Prop_Field<&Render_Scene_3D::Prop::view_active, "view_active", "Whether the scene publishes rendered frames.">, detail::State_Field, detail::State_Field, detail::State_Field>; using Visual_Adapter = detail::Renderable_Adapter, detail::Prop_Field<&Prop::visible, "visible", "Whether the visual participates in rendering.">, detail::Prop_Field<&Prop::depth_test, "depth_test", "Whether fragments use depth testing.">, detail::Prop_Field<&Prop::items, "items", "Editable item collection represented by this visual.">, detail::State_Field, detail::State_Field, detail::State_Field>; descriptors_.push_back(detail::make_renderable_descriptor("scene", "3D 场景", "scene", Scene_Adapter{scene})); descriptors_.push_back(detail::make_renderable_descriptor("visual", std::move(label), "visual", Visual_Adapter{*visual_})); } [[nodiscard]] nlohmann::json schema() const override { nlohmann::json components = nlohmann::json::array(); for (const auto& descriptor : descriptors_) components.push_back(descriptor->schema()); return {{"protocol", "aethera.plot.inspector"}, {"version", 2}, {"components", std::move(components)}}; } [[nodiscard]] nlohmann::json write_prop(std::string_view component, std::string_view key, const nlohmann::json& value) override { const auto found = std::ranges::find_if(descriptors_, [&](const auto& descriptor) { return descriptor->id() == component; }); if (found == descriptors_.end()) return {{"success", false}, {"error", "unknown component"}}; auto result = (*found)->write_prop(key, value); result["component"] = component; return result; } void update(const Plot_Frame_Request&) override {} private: std::unique_ptr visual_; /* Scene 引用的 Visual 唯一所有者。 */ std::vector> descriptors_; /* Prop/State 协议描述。 */ }; template std::shared_ptr make_visual_plot(asio::any_io_executor executor, std::string label, Build_Result build_result) { using Visual_Object = Impl; if (!build_result) throw std::logic_error("3D Gallery visual dependency graph is invalid"); auto visual = std::move(build_result).value(); auto scene_result = Scene_3D::Builder(visual.get()) .set(&Render_Scene_3D::Prop::viewport, Extent{720, 420}) .set(&Render_Scene_3D::Prop::clear_color, Linear_Color{0.018F, 0.027F, 0.047F, 1.0F}) .set(&Render_Scene_3D::Prop::view_active, true) .build(); if (!scene_result) throw std::logic_error("3D Gallery scene dependency graph is invalid"); auto scene = std::move(scene_result).value(); auto view = std::make_unique>(*scene, std::move(visual), std::move(label)); return std::make_shared(std::move(executor), std::move(scene), std::move(view)); } Color color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 255) { return {red, green, blue, alpha}; } } std::shared_ptr make_datoviz_point_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Point Visual", Impl::Builder{} .set(&Point_Visual::Prop::items, std::vector{{{-0.65F, -0.25F, 0.05F}, color(255, 91, 110), 28.0F}, {{0.0F, 0.58F, 0.25F}, color(82, 226, 190), 34.0F}, {{0.62F, -0.12F, -0.15F}, color(75, 145, 255), 30.0F}}).build()); } std::shared_ptr make_datoviz_splat_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Splat Visual", Impl::Builder{} .set(&Splat_Visual::Prop::items, std::vector{{{-0.48F, 0.0F, 0.1F}, color(255, 98, 115, 210), {0.18F, 0.08F}, 0.45F}, {{0.28F, 0.15F, 0.0F}, color(66, 218, 188, 210), {0.12F, 0.22F}, -0.3F}, {{0.15F, -0.38F, 0.2F}, color(76, 132, 255, 210), {0.2F, 0.1F}, 0.9F}}).build()); } std::shared_ptr make_datoviz_pixel_plot(asio::any_io_executor executor) { std::vector pixels; for (int y = -8; y <= 8; ++y) for (int x = -12; x <= 12; ++x) pixels.push_back({{x / 13.0F, y / 9.0F, 0.12F * std::sin(x * .45F) * std::cos(y * .35F)}, color(static_cast(90 + 6 * (x + 12)), static_cast(100 + 8 * (y + 8)), 230), 5.0F}); return make_visual_plot(std::move(executor), "Pixel Visual", Impl::Builder{}.set(&Pixel_Visual::Prop::items, std::move(pixels)).build()); } std::shared_ptr make_datoviz_marker_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Marker Visual", Impl::Builder{} .set(&Marker_Visual::Prop::items, std::vector{{{-0.7F, 0.0F, 0.0F}, color(255, 93, 115), 34.0F, 0.0F, Marker_Shape::disc}, {{-0.35F, 0.25F, 0.1F}, color(91, 226, 193), 36.0F, 0.25F, Marker_Shape::square}, {{0.0F, -0.2F, 0.2F}, color(100, 158, 255), 38.0F, 0.5F, Marker_Shape::triangle}, {{0.35F, 0.25F, 0.1F}, color(250, 195, 92), 40.0F, 0.75F, Marker_Shape::diamond}, {{0.7F, 0.0F, 0.0F}, color(201, 132, 255), 42.0F, 1.0F, Marker_Shape::cross}}).build()); } std::shared_ptr make_datoviz_sphere_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Sphere Visual", Impl::Builder{} .set(&Sphere_Visual::Prop::items, std::vector{{{-0.48F, -0.2F, 0.0F}, color(255, 91, 110), 0.28F}, {{0.08F, 0.25F, 0.18F}, color(82, 226, 190), 0.36F}, {{0.55F, -0.18F, -0.12F}, color(75, 145, 255), 0.24F}}).build()); } std::shared_ptr make_datoviz_segment_plot(asio::any_io_executor executor) { std::vector segments; for (int index = 0; index < 12; ++index) { const float angle = static_cast(index) * std::numbers::pi_v / 6.0F; segments.push_back({{0.0F, 0.0F, 0.0F}, {0.82F * std::cos(angle), 0.82F * std::sin(angle), 0.18F * std::sin(2 * angle)}, color(static_cast(80 + index * 13), static_cast(220 - index * 8), 240), 4.0F}); } return make_visual_plot(std::move(executor), "Segment Visual", Impl::Builder{}.set(&Segment_Visual::Prop::items, std::move(segments)).build()); } std::shared_ptr make_datoviz_vector_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Vector Visual", Impl::Builder{} .set(&Vector_Visual::Prop::items, std::vector{{{-0.55F, -0.35F, 0.0F}, {0.55F, 0.2F, 0.25F}, color(255, 98, 115), 4.0F}, {{-0.1F, 0.0F, 0.0F}, {0.2F, 0.62F, 0.18F}, color(80, 225, 190), 5.0F}, {{0.35F, -0.25F, 0.0F}, {-0.12F, 0.25F, 0.65F}, color(78, 145, 255), 4.0F}}).build()); } std::shared_ptr make_datoviz_primitive_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Primitive Visual", Impl::Builder{} .set(&Primitive_Visual::Prop::topology, Primitive_Topology::triangle_list) .set(&Primitive_Visual::Prop::items, std::vector{{{-0.72F, -0.55F, 0.0F}, color(255, 86, 110), {0, 0, 1}}, {{0.72F, -0.55F, 0.0F}, color(75, 145, 255), {0, 0, 1}}, {{0.0F, 0.72F, 0.25F}, color(82, 226, 190), {0, 0, 1}}}).build()); } std::shared_ptr make_datoviz_mesh_plot(asio::any_io_executor executor) { const std::vector mesh{{{-0.65F, -0.55F, 0.0F}, color(255, 94, 112), {0, 0, 1}, {0, 0}}, {{0.65F, -0.55F, 0.0F}, color(75, 145, 255), {0, 0, 1}, {1, 0}}, {{0.65F, 0.55F, 0.0F}, color(82, 226, 190), {0, 0, 1}, {1, 1}}, {{-0.65F, -0.55F, 0.0F}, color(255, 94, 112), {0, 0, 1}, {0, 0}}, {{0.65F, 0.55F, 0.0F}, color(82, 226, 190), {0, 0, 1}, {1, 1}}, {{-0.65F, 0.55F, 0.0F}, color(244, 190, 86), {0, 0, 1}, {0, 1}}}; return make_visual_plot(std::move(executor), "Mesh Visual", Impl::Builder{}.set(&Mesh_Visual::Prop::items, mesh).build()); } std::shared_ptr make_datoviz_path_plot(asio::any_io_executor executor) { std::vector path; for (int index = 0; index < 64; ++index) { const float t = static_cast(index) / 63.0F; path.push_back({{-0.9F + 1.8F * t, 0.48F * std::sin(t * 4.0F * std::numbers::pi_v), 0.25F * std::cos(t * 2.0F * std::numbers::pi_v)}, color(static_cast(70 + 170 * t), static_cast(220 - 80 * t), 245), 5.0F}); } return make_visual_plot(std::move(executor), "Path Visual", Impl::Builder{}.set(&Path_Visual::Prop::items, std::move(path)).build()); } std::shared_ptr make_datoviz_image_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Image Visual", Impl::Builder{} .set(&Image_Visual::Prop::field_width, 32U).set(&Image_Visual::Prop::field_height, 32U) .set(&Image_Visual::Prop::items, std::vector{{{0.0F, 0.0F, 0.0F}, {1.45F, 1.0F}, {0, 0, 1, 1}, color(255, 255, 255)}}).build()); } std::shared_ptr make_datoviz_labels_plot(asio::any_io_executor executor) { return make_visual_plot(std::move(executor), "Labels Visual", Impl::Builder{} .set(&Labels_Visual::Prop::field_width, 8U).set(&Labels_Visual::Prop::field_height, 8U) .set(&Labels_Visual::Prop::items, std::vector