12 Eigen::Index samples_per_segment)
13 : m_default_mode(
mode)
14 , m_default_samples_per_segment(samples_per_segment)
17 "PathOperator created with mode {}, {} samples per segment",
18 static_cast<int>(
mode), samples_per_segment);
27 if (vertices.empty()) {
29 "Cannot initialize PathOperator with zero vertices");
37 "PathOperator initialized with {} control vertices", vertices.size());
45 const std::vector<std::vector<LineVertex>>& paths,
48 for (
const auto& path : paths) {
53 "PathOperator initialized with {} paths",
58 const std::vector<LineVertex>& control_vertices,
61 if (control_vertices.empty()) {
63 "Cannot add path with zero control vertices");
67 auto path = std::make_shared<GpuSync::PathGeneratorNode>(
69 default_samples_per_segment,
73 path->set_control_points(control_vertices);
75 path->compute_frame();
77 uint32_t expected = 0;
79 std::memory_order_acquire, std::memory_order_relaxed)) {
80 if (
m_shutdown.load(std::memory_order_relaxed))
85 m_paths.push_back(std::move(path));
90 "Added path #{} with {} control vertices, {} generated vertices",
91 m_paths.size(), control_vertices.size(),
92 m_paths.back()->get_generated_vertex_count());
99 "PathOperator::add_node: null node ignored");
103 node->compute_frame();
105 uint32_t expected = 0;
107 std::memory_order_acquire, std::memory_order_relaxed)) {
108 if (
m_shutdown.load(std::memory_order_relaxed))
113 m_paths.push_back(std::move(node));
118 "PathOperator: added node #{} ({} vertices)",
128 uint32_t expected = 0;
130 std::memory_order_acquire, std::memory_order_relaxed)) {
131 if (
m_shutdown.load(std::memory_order_relaxed))
137 path->compute_frame();
151 for (
const auto& path :
m_paths) {
152 const auto points = path->get_control_points();
164 return m_paths[idx]->get_vertex_data();
170 for (
const auto& group :
m_paths) {
171 auto span = group->get_vertex_data();
174 span.begin(), span.end());
185 auto layout_opt =
m_paths[0]->get_vertex_layout();
190 auto layout = *layout_opt;
200 return m_paths[0]->get_primitive_topology();
206 for (
const auto& path :
m_paths) {
207 total += path->get_vertex_count();
214 return std::ranges::any_of(
216 [](
const auto& group) {
return group->needs_gpu_update(); });
222 path->clear_gpu_update_flag();
228 std::vector<DirtyVertexRange> ranges;
232 for (
const auto& path :
m_paths) {
233 const auto count =
static_cast<uint32_t
>(path->get_vertex_count());
234 if (path->needs_gpu_update()) {
238 .vertex_count =
count });
249 std::vector<DrawRun> runs;
252 for (
const auto& path :
m_paths) {
253 const auto count =
static_cast<uint32_t
>(path->get_vertex_count());
254 const auto topo = path->get_primitive_topology();
256 if (!runs.empty() && runs.back().topology == topo && is_concatenable_topology(topo)) {
257 runs.back().vertex_count +=
count;
271 for (
const auto& path :
m_paths) {
272 total += path->get_all_vertex_count();
286 uint32_t cluster = 0;
287 for (
const auto& path :
m_paths) {
288 const size_t count = path->get_vertex_count();
305 if (param ==
"tension") {
307 path->set_tension(
value);
309 }
else if (param ==
"samples_per_segment") {
312 path->set_samples_per_segment(
static_cast<Eigen::Index
>(
value));
314 }
else if (param ==
"thickness") {
324 if (query ==
"control_point_count") {
326 for (
const auto& path :
m_paths) {
327 total += path->get_control_point_count();
329 return static_cast<double>(
total);
331 if (query ==
"vertex_count") {
334 if (query ==
"path_count") {
335 return static_cast<double>(
m_paths.size());
348 path->set_samples_per_segment(samples);
355 path->set_tension(tension);
363 path->set_path_thickness(thickness);
370 path->set_path_color(
color);
377 for (
const auto& path :
m_paths) {
378 total += path->get_control_point_count();
386 uint32_t expected = 0;
388 std::memory_order_acquire, std::memory_order_relaxed)) {
389 if (
m_shutdown.load(std::memory_order_relaxed))
394 auto first = vertices.begin();
396 const auto count =
static_cast<std::ptrdiff_t
>(path->get_control_point_count());
397 path->set_control_points(std::vector<LineVertex>(first, first +
count));
398 path->compute_frame();
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
std::vector< glm::vec2 > * points
std::vector< uint64_t > ids
std::vector< glm::vec3 > positions
void set_parameter(std::string_view param, double value) override
Set operator parameter.
void * get_data_at(size_t global_index) override
Get mutable access to point at global index.
std::vector< DrawRun > topology_runs() const override
Coalesces adjacent paths sharing a concatenable topology into one run.
std::vector< uint8_t > m_vertex_data_aggregate
Kinesis::InterpolationMode m_default_mode
std::vector< DirtyVertexRange > dirty_vertex_ranges() const override
One DirtyVertexRange per path whose PathGeneratorNode needs a GPU update, so add_control_point() on o...
void add_path(const std::vector< LineVertex > &control_vertices, Kinesis::InterpolationMode mode, uint32_t default_samples_per_segment=32, size_t max_control_points=64, double tension=0.5)
Add a new path with given control points and properties.
bool is_vertex_data_dirty() const override
Check if geometry changed this frame.
void initialize_paths(const std::vector< std::vector< LineVertex > > &paths, Kinesis::InterpolationMode mode)
Initialize multiple paths with given control points and properties.
std::vector< std::shared_ptr< GpuSync::PathGeneratorNode > > m_paths
void add_node(std::shared_ptr< GpuSync::PathGeneratorNode > node)
Add an externally constructed PathGeneratorNode subtype to the operator.
std::atomic< uint32_t > m_access_token
Eigen::Index m_default_samples_per_segment
void set_tension(double tension)
Set the tension parameter for all paths (if supported by mode).
float m_default_thickness
size_t get_vertex_count() const override
Get number of vertices (may differ from point count for topology/path)
PathOperator(Kinesis::InterpolationMode mode=Kinesis::InterpolationMode::CATMULL_ROM, Eigen::Index samples_per_segment=32)
size_t get_point_count() const override
Get source point count (before topology expansion)
Kakshya::VertexLayout get_vertex_layout() const override
Get vertex layout describing vertex structure.
void set_samples_per_segment(Eigen::Index samples)
Set the number of samples per segment for all paths.
std::optional< Portal::Graphics::PrimitiveTopology > declared_topology() const override
Forwards to the first path's own get_primitive_topology().
void set_global_color(const glm::vec3 &color)
Set the global color tint for all paths.
std::atomic< bool > m_shutdown
void set_vertices(const std::vector< LineVertex > &vertices)
Replace every control point, in extract_vertices() order, keeping the paths.
void initialize(const std::vector< LineVertex > &vertices)
Initialize a single path with given control points and properties.
void process(float dt) override
Process for one batch cycle.
std::vector< uint32_t > build_cluster_ids() const override
Overrides GraphicsOperator::build_cluster_ids() for real multi-path scenes.
void mark_vertex_data_clean() override
Clear dirty flag after GPU upload.
std::span< const uint8_t > get_vertex_data_for_collection(uint32_t idx) const override
Get vertex data for specific collection (if multiple)
std::vector< LineVertex > extract_vertices() const
Extract current vertex data as LineVertex array.
void set_global_thickness(float thickness)
Set the global thickness for all paths.
std::span< const uint8_t > get_vertex_data() const override
Get vertex data for GPU upload.
std::optional< double > query_state(std::string_view query) const override
Query operator internal state.
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
InterpolationMode
Mathematical interpolation methods.
uint32_t vertex_count
Total number of vertices in this buffer.
Complete description of vertex data layout in a buffer.
A contiguous span of vertex records that changed since the last mark_vertex_data_clean().
PrimitiveTopology topology
One contiguous span of vertices sharing a primitive topology.