169 lines
13 KiB
C++
169 lines
13 KiB
C++
#include "Gallery_Plots.hpp"
|
|
#include "Renderable_Adapter.hpp"
|
|
#include <render_3D/Render_3D.hpp>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <numbers>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace aethera::web {
|
|
namespace {
|
|
using namespace render_3d;
|
|
using Scene_3D = Impl<Render_Scene_3D>;
|
|
|
|
template <typename Visual_Object>
|
|
class Visual_Scene_View final : public Plot::Scene_View {
|
|
public:
|
|
Visual_Scene_View(Scene_3D& scene, std::unique_ptr<Visual_Object> 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<Scene_3D,
|
|
detail::Prop_Field<&Render_Scene_3D::Prop::clear_color, "clear_color", "Linear scene clear color.">,
|
|
detail::Prop_Field<&Render_Scene_3D::Prop::view_active, "view_active", "Whether the scene publishes rendered frames.">,
|
|
detail::State_Field<Scene::Base_Tag, &Scene::State::renderable_count, "renderable_count", "Number of renderables attached to the scene.">,
|
|
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_task_count, "taskflow_task_count", "Number of tasks in the scene graph.">,
|
|
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_execution_time_ns, "taskflow_execution_time_ns", "Scene graph execution time in nanoseconds.">>;
|
|
using Visual_Adapter = detail::Renderable_Adapter<Visual_Object,
|
|
detail::Prop_Field<&Prop::transform, "transform", "World transform applied to the complete visual.">,
|
|
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<Definition::Base_Tag, &State::item_count, "item_count", "Number of published input items.">,
|
|
detail::State_Field<Definition::Base_Tag, &State::prepared_item_count, "prepared_item_count", "Number of prepared backend items.">,
|
|
detail::State_Field<Definition::Base_Tag, &State::prepared_revision, "prepared_revision", "Property revision represented by prepared GPU data.">>;
|
|
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_Object> visual_; /* Scene 引用的 Visual 唯一所有者。 */
|
|
std::vector<std::unique_ptr<detail::Renderable_Descriptor>> descriptors_; /* Prop/State 协议描述。 */
|
|
};
|
|
|
|
template <typename Definition, typename Build_Result>
|
|
std::shared_ptr<Plot> make_visual_plot(asio::any_io_executor executor, std::string label, Build_Result build_result) {
|
|
using Visual_Object = Impl<Definition>;
|
|
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<Visual_Scene_View<Visual_Object>>(*scene, std::move(visual), std::move(label));
|
|
return std::make_shared<Plot>(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<Plot> make_datoviz_point_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Point_Visual>(std::move(executor), "Point Visual", Impl<Point_Visual>::Builder{}
|
|
.set(&Point_Visual::Prop::items, std::vector<Point>{{{-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<Plot> make_datoviz_splat_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Splat_Visual>(std::move(executor), "Splat Visual", Impl<Splat_Visual>::Builder{}
|
|
.set(&Splat_Visual::Prop::items, std::vector<Splat>{{{-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<Plot> make_datoviz_pixel_plot(asio::any_io_executor executor) {
|
|
std::vector<Pixel> 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<std::uint8_t>(90 + 6 * (x + 12)), static_cast<std::uint8_t>(100 + 8 * (y + 8)), 230), 5.0F});
|
|
return make_visual_plot<Pixel_Visual>(std::move(executor), "Pixel Visual", Impl<Pixel_Visual>::Builder{}.set(&Pixel_Visual::Prop::items, std::move(pixels)).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_marker_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Marker_Visual>(std::move(executor), "Marker Visual", Impl<Marker_Visual>::Builder{}
|
|
.set(&Marker_Visual::Prop::items, std::vector<Marker>{{{-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<Plot> make_datoviz_sphere_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Sphere_Visual>(std::move(executor), "Sphere Visual", Impl<Sphere_Visual>::Builder{}
|
|
.set(&Sphere_Visual::Prop::items, std::vector<Sphere>{{{-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<Plot> make_datoviz_segment_plot(asio::any_io_executor executor) {
|
|
std::vector<Segment> segments;
|
|
for (int index = 0; index < 12; ++index) { const float angle = static_cast<float>(index) * std::numbers::pi_v<float> / 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<std::uint8_t>(80 + index * 13), static_cast<std::uint8_t>(220 - index * 8), 240), 4.0F}); }
|
|
return make_visual_plot<Segment_Visual>(std::move(executor), "Segment Visual", Impl<Segment_Visual>::Builder{}.set(&Segment_Visual::Prop::items, std::move(segments)).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_vector_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Vector_Visual>(std::move(executor), "Vector Visual", Impl<Vector_Visual>::Builder{}
|
|
.set(&Vector_Visual::Prop::items, std::vector<Vector_Glyph>{{{-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<Plot> make_datoviz_primitive_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Primitive_Visual>(std::move(executor), "Primitive Visual", Impl<Primitive_Visual>::Builder{}
|
|
.set(&Primitive_Visual::Prop::topology, Primitive_Topology::triangle_list)
|
|
.set(&Primitive_Visual::Prop::items, std::vector<Primitive_Vertex>{{{-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<Plot> make_datoviz_mesh_plot(asio::any_io_executor executor) {
|
|
const std::vector<Mesh_Vertex> 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<Mesh_Visual>(std::move(executor), "Mesh Visual", Impl<Mesh_Visual>::Builder{}.set(&Mesh_Visual::Prop::items, mesh).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_path_plot(asio::any_io_executor executor) {
|
|
std::vector<Path_Vertex> path;
|
|
for (int index = 0; index < 64; ++index) { const float t = static_cast<float>(index) / 63.0F; path.push_back({{-0.9F + 1.8F * t, 0.48F * std::sin(t * 4.0F * std::numbers::pi_v<float>), 0.25F * std::cos(t * 2.0F * std::numbers::pi_v<float>)}, color(static_cast<std::uint8_t>(70 + 170 * t), static_cast<std::uint8_t>(220 - 80 * t), 245), 5.0F}); }
|
|
return make_visual_plot<Path_Visual>(std::move(executor), "Path Visual", Impl<Path_Visual>::Builder{}.set(&Path_Visual::Prop::items, std::move(path)).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_image_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Image_Visual>(std::move(executor), "Image Visual", Impl<Image_Visual>::Builder{}
|
|
.set(&Image_Visual::Prop::field_width, 32U).set(&Image_Visual::Prop::field_height, 32U)
|
|
.set(&Image_Visual::Prop::items, std::vector<Image>{{{0.0F, 0.0F, 0.0F}, {1.45F, 1.0F}, {0, 0, 1, 1}, color(255, 255, 255)}}).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_labels_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Labels_Visual>(std::move(executor), "Labels Visual", Impl<Labels_Visual>::Builder{}
|
|
.set(&Labels_Visual::Prop::field_width, 8U).set(&Labels_Visual::Prop::field_height, 8U)
|
|
.set(&Labels_Visual::Prop::items, std::vector<Label>{{{-0.55F, 0.28F, 0.0F}, 0, {72, 34}, color(255, 255, 255)}, {{0.5F, 0.25F, 0.1F}, 1, {72, 34}, color(255, 255, 255)}, {{-0.45F, -0.32F, 0.1F}, 2, {72, 34}, color(255, 255, 255)}, {{0.55F, -0.3F, 0.0F}, 3, {72, 34}, color(255, 255, 255)}}).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_glyph_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Glyph_Visual>(std::move(executor), "Glyph Visual", Impl<Glyph_Visual>::Builder{}
|
|
.set(&Glyph_Visual::Prop::field_width, 32U).set(&Glyph_Visual::Prop::field_height, 32U)
|
|
.set(&Glyph_Visual::Prop::items, std::vector<Glyph>{{{-0.55F, -0.15F, 0.0F}, {-0.18F, -0.18F, 0.18F, 0.18F}, {0, 0, 1, 1}, color(255, 100, 120), -0.2F}, {{0.0F, 0.22F, 0.1F}, {-0.22F, -0.22F, 0.22F, 0.22F}, {0, 0, 1, 1}, color(82, 226, 190), 0.25F}, {{0.55F, -0.15F, 0.0F}, {-0.2F, -0.2F, 0.2F, 0.2F}, {0, 0, 1, 1}, color(80, 145, 255), 0.55F}}).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_text_plot(asio::any_io_executor executor) {
|
|
return make_visual_plot<Text_Visual>(std::move(executor), "Text Visual", Impl<Text_Visual>::Builder{}
|
|
.set(&Text_Visual::Prop::items, std::vector<Text_Label>{{{-0.72F, 0.28F, 0.0F}, "Aethera", color(82, 226, 190), 28.0F}, {{-0.62F, -0.15F, 0.1F}, "Datoviz Visual", color(90, 155, 255), 22.0F}}).build());
|
|
}
|
|
|
|
std::shared_ptr<Plot> make_datoviz_volume_plot(asio::any_io_executor executor) {
|
|
std::vector<Voxel> voxels(16U * 16U * 16U);
|
|
for (std::size_t index = 0; index < voxels.size(); ++index) voxels[index].value = static_cast<float>(index % 256U) / 255.0F;
|
|
return make_visual_plot<Volume_Visual>(std::move(executor), "Volume Visual", Impl<Volume_Visual>::Builder{}
|
|
.set(&Volume_Visual::Prop::field_width, 16U).set(&Volume_Visual::Prop::field_height, 16U).set(&Volume_Visual::Prop::field_depth, 16U)
|
|
.set(&Volume_Visual::Prop::items, std::move(voxels)).build());
|
|
}
|
|
}
|