MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MayaFlux::Nodes::GpuSync::PathGeneratorNode Class Reference

Generates dense vertex paths from sparse control points or freehand drawing. More...

#include <PathGeneratorNode.hpp>

+ Inheritance diagram for MayaFlux::Nodes::GpuSync::PathGeneratorNode:
+ Collaboration diagram for MayaFlux::Nodes::GpuSync::PathGeneratorNode:

Public Types

using CustomPathFunction = std::function< glm::vec3(std::span< const LineVertex >, double)>
 

Public Member Functions

void add_control_point (const LineVertex &vertex)
 Add control point with full LineVertex data.
 
void clear_path ()
 Clear all control points and generated vertices.
 
void complete ()
 Finish incremental drawing stroke.
 
void compute_frame () override
 Compute frame - generates interpolated vertices from control points.
 
void draw_to (const LineVertex &vertex)
 Extend path with full LineVertex data.
 
void force_uniform_color (bool should_force)
 Set uniform color mode.
 
void force_uniform_thickness (bool should_force)
 Set uniform thickness mode.
 
size_t get_all_vertex_count () const
 Get combined vertex count (control points + completed strokes + in-progress stroke)
 
const std::vector< LineVertex > & get_all_vertices () const
 Get all generated vertices (control points + completed strokes + in-progress stroke)
 
LineVertex get_control_point (size_t index) const
 Get control point.
 
size_t get_control_point_capacity () const
 Get maximum control point capacity.
 
size_t get_control_point_count () const
 Get number of control points currently stored.
 
std::vector< LineVertexget_control_points () const
 Get all control points as vector.
 
size_t get_generated_vertex_count () const
 Get number of generated vertices.
 
const glm::vec3 & get_path_color () const
 Get current path color.
 
const float & get_path_thickness () const
 Get current path thickness.
 
Portal::Graphics::PrimitiveTopology get_primitive_topology () const override
 Get primitive topology for rendering.
 
void parameterize_arc_length (bool enable)
 Enable/disable arc-length parameterization.
 
 PathGeneratorNode (CustomPathFunction custom_func, Eigen::Index samples_per_segment=32, size_t max_control_points=64)
 Create path generator with custom interpolation function.
 
 PathGeneratorNode (Kinesis::InterpolationMode mode=Kinesis::InterpolationMode::QUADRATIC_BEZIER, Eigen::Index samples_per_segment=32, size_t max_control_points=64, double tension=0.5)
 Create path generator with interpolation mode.
 
void set_control_points (const std::vector< LineVertex > &vertices)
 Set all control points with full LineVertex data.
 
void set_interpolation_mode (Kinesis::InterpolationMode mode)
 Set interpolation mode.
 
void set_path_color (const glm::vec3 &color, bool force_uniform=true)
 Set path color (applied to all generated vertices)
 
void set_path_thickness (float thickness, bool force_uniform=true)
 Set path thickness (applied to all generated vertices)
 
void set_primitive_topology (Portal::Graphics::PrimitiveTopology topology)
 Set primitive topology for rendering.
 
void set_samples_per_segment (Eigen::Index samples)
 Set samples per segment.
 
void set_tension (double tension)
 Set tension parameter (for Catmull-Rom)
 
bool should_force_uniform_color () const
 Check if uniform color mode is enabled.
 
void update_control_point (size_t index, const LineVertex &vertex)
 Update specific control point with full LineVertex data.
 
- Public Member Functions inherited from MayaFlux::Nodes::GpuSync::GeometryWriterNode
void clear ()
 Clear vertex buffer and reset count.
 
void clear_and_resize (uint32_t vertex_count)
 Clear vertex buffer and resize to specified count.
 
void clear_gpu_update_flag () override
 Clear the dirty flag after GPU upload completes.
 
void clear_layout_update_flag ()
 Clear layout update flag.
 
 GeometryWriterNode (uint32_t initial_capacity=1024)
 Constructor.
 
uint32_t get_index_count () const
 Get number of indices in index buffer.
 
std::span< const uint32_t > get_index_data () const
 Get raw index buffer data.
 
NodeContextget_last_context () override
 Retrieves the last created context object.
 
std::span< const uint8_t > get_vertex (uint32_t vertex_index) const
 Get a single vertex by index.
 
size_t get_vertex_buffer_size_bytes () const
 Get vertex buffer size in bytes.
 
uint32_t get_vertex_count () const
 Get number of vertices.
 
std::span< const uint8_t > get_vertex_data () const
 Get raw vertex buffer data.
 
std::optional< Kakshya::VertexLayoutget_vertex_layout () const
 Get cached vertex layout.
 
size_t get_vertex_stride () const
 Get stride (bytes per vertex)
 
template<typename T >
get_vertex_typed (uint32_t index) const
 Get a single vertex by index as typed data.
 
bool has_indices () const
 Check if index buffer has been set.
 
void mark_vertex_data_dirty (bool state)
 Set vertex data dirty flag.
 
bool needs_gpu_update () const override
 Check if vertex data or layout changed since last GPU sync.
 
bool needs_layout_update () const
 Check if layout needs update.
 
bool needs_vertex_data_update () const
 Check if vertex data has changed since last GPU sync.
 
std::vector< double > process_batch (unsigned int num_samples) override
 Process batch for geometry generation.
 
void resize_vertex_buffer (uint32_t vertex_count, bool preserve_data=false)
 Resize vertex buffer to hold specified number of vertices.
 
void restore_state () override
 Restore saved geometry state.
 
void save_state () override
 Save current geometry state.
 
void set_indices (std::span< const uint32_t > indices)
 Set index buffer for indexed drawing.
 
void set_vertex (uint32_t vertex_index, const void *data, size_t size_bytes)
 Set a single vertex by index.
 
void set_vertex_data (const void *data, size_t size_bytes)
 Copy raw vertex data into buffer.
 
void set_vertex_layout (const Kakshya::VertexLayout &layout)
 Set cached vertex layout.
 
void set_vertex_stride (size_t stride)
 Set vertex stride (bytes per vertex)
 
template<typename T >
void set_vertex_typed (uint32_t index, const T &vertex)
 Set a single vertex by index from typed data.
 
template<typename T >
void set_vertices (std::span< const T > vertices)
 Set multiple vertices from typed array.
 
void update_context (double value) override
 Updates the context object with the current node state.
 
 ~GeometryWriterNode () override=default
 
- Public Member Functions inherited from MayaFlux::Nodes::GpuSync::GpuSync
std::vector< double > process_batch (unsigned int num_samples) override
 Batch processing for GPU nodes.
 
double process_sample (double) override
 Single sample processing hook.
 
 ~GpuSync () override=default
 
- Public Member Functions inherited from MayaFlux::Nodes::Node
void add_buffer_reference ()
 Increments the buffer reference count This method is called when a new buffer starts using this node to ensure proper lifecycle management.
 
uint64_t get_active_snapshot_context () const
 Get the active snapshot context ID.
 
const std::atomic< uint32_t > & get_channel_mask () const
 Retrieves the current bitmask of active channels using this node.
 
uint32_t get_frame_rate () const
 
std::span< const float > get_gpu_data_buffer () const
 Provides access to the GPU data buffer.
 
virtual double get_last_output ()
 Retrieves the most recent output value produced by the node.
 
RoutingStateget_routing_state ()
 Retrieves the current routing state of the network (non-const)
 
const RoutingStateget_routing_state () const
 Retrieves the current routing state of the network.
 
uint32_t get_sample_rate () const
 
bool has_active_snapshot () const
 Check if node is currently being snapshotted by any context.
 
bool has_capability (NodeCapability cap) const
 Query a single capability.
 
bool is_buffer_processed () const
 Checks if the buffer has been processed.
 
bool is_gpu_compatible () const
 Checks if the node supports GPU processing.
 
bool is_in_network () const
 Sets whether the node is part of a NodeNetwork.
 
bool is_in_snapshot_context (uint64_t context_id) const
 Check if currently in a snapshot context.
 
bool is_used_by_channel (uint32_t channel_id) const
 Checks if the node is currently used by a specific channel.
 
bool mark_buffer_processed ()
 Marks the node as having been processed by a buffer.
 
bool needs_channel_routing () const
 Checks if the network is currently in a routing transition phase.
 
virtual uint8_t node_capabilities () const
 Declare which data shapes this node's context can produce.
 
virtual void on_tick (const NodeHook &callback)
 Registers a callback to be called on each tick.
 
virtual void on_tick_if (const NodeCondition &condition, const NodeHook &callback)
 Registers a conditional callback.
 
void register_channel_usage (uint32_t channel_id)
 Mark the specificed channel as a processor/user.
 
void release_snapshot_context (uint64_t context_id)
 Release snapshot context.
 
virtual void remove_all_hooks ()
 Removes all registered callbacks.
 
void remove_buffer_reference ()
 Decrements the buffer reference count This method is called when a buffer stops using this node to ensure proper lifecycle management.
 
virtual bool remove_conditional_hook (const NodeCondition &callback)
 Removes a previously registered conditional callback.
 
virtual bool remove_hook (const NodeHook &callback)
 Removes a previously registered callback.
 
void request_buffer_reset ()
 Requests a reset of the buffer state.
 
void request_reset_from_channel (uint32_t channel_id)
 Requests a reset of the processed state from a specific channel.
 
virtual void reset_processed_state ()
 Resets the processed state of the node and any attached input nodes.
 
void set_frame_rate (uint32_t frame_rate)
 
virtual void set_gpu_compatible (bool compatible)
 Sets whether the node is compatible with GPU processing.
 
void set_in_network (bool networked)
 Marks the node as being part of a NodeNetwork.
 
void set_sample_rate (uint32_t sample_rate)
 
bool try_claim_snapshot_context (uint64_t context_id)
 Attempt to claim snapshot context for this processing cycle.
 
void unregister_channel_usage (uint32_t channel_id)
 Removes the specified channel from the usage tracking.
 
virtual ~Node ()=default
 Virtual destructor for proper cleanup of derived classes.
 

Private Member Functions

void append_line_segment (const LineVertex &v0, const LineVertex &v1, std::vector< LineVertex > &output)
 
void generate_curve_segment (const std::vector< LineVertex > &curve_verts, size_t start_idx, std::vector< LineVertex > &output)
 
void generate_custom_path ()
 
void generate_direct_path ()
 
void generate_interpolated_path ()
 
void generate_path_vertices ()
 
void regenerate_geometry ()
 
void regenerate_segment_range (size_t start_ctrl_idx, size_t end_ctrl_idx)
 

Private Attributes

bool m_arc_length_parameterization {}
 
std::vector< LineVertexm_combined_cache
 
std::vector< LineVertexm_completed_draws
 
Memory::HistoryBuffer< LineVertexm_control_points
 
glm::vec3 m_current_color { 1.0F, 1.0F, 1.0F }
 
float m_current_thickness { 2.0F }
 
CustomPathFunction m_custom_func
 
size_t m_dirty_segment_end { INVALID_SEGMENT }
 
size_t m_dirty_segment_start { INVALID_SEGMENT }
 
std::vector< LineVertexm_draw_vertices
 
std::vector< LineVertexm_draw_window
 
bool m_force_uniform_color {}
 
bool m_force_uniform_thickness {}
 
bool m_geometry_dirty { true }
 
Kinesis::InterpolationMode m_mode
 
Portal::Graphics::PrimitiveTopology m_primitive_topology { Portal::Graphics::PrimitiveTopology::LINE_STRIP }
 
Eigen::Index m_samples_per_segment
 
double m_tension
 
std::vector< LineVertexm_vertices
 

Static Private Attributes

static constexpr size_t INVALID_SEGMENT { std::numeric_limits<size_t>::max() }
 

Additional Inherited Members

- Public Attributes inherited from MayaFlux::Nodes::Node
bool m_fire_events_during_snapshot = false
 Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don't fire during isolated buffer processing) Can be exposed in future if needed via concrete implementation in parent.
 
std::atomic< uint32_t > m_modulator_count { 0 }
 Counter tracking how many other nodes are using this node as a modulator.
 
std::atomic< NodeStatem_state { NodeState::INACTIVE }
 Atomic state flag tracking the node's processing status.
 
- Protected Member Functions inherited from MayaFlux::Nodes::GpuSync::GpuSync
void notify_tick (double) override
 GPU sync nodes don't emit tick callbacks.
 
- Protected Member Functions inherited from MayaFlux::Nodes::Node
virtual void reset_processed_state_internal ()
 Resets the processed state of the node directly.
 
- Protected Attributes inherited from MayaFlux::Nodes::GpuSync::GeometryWriterNode
GeometryContext m_context { 0.0, {}, 0, 0 }
 
std::vector< uint32_t > m_index_buffer
 Optional index buffer for indexed drawing (not used by default)
 
bool m_needs_layout_update {}
 Flag indicating if layout needs update.
 
std::vector< uint8_t > m_vertex_buffer
 Vertex data buffer (flat array of bytes)
 
uint32_t m_vertex_count {}
 Number of vertices in buffer.
 
bool m_vertex_data_dirty { true }
 Flag: vertex data or layout changed since last GPU upload.
 
std::optional< Kakshya::VertexLayoutm_vertex_layout
 Cached vertex layout for descriptor binding.
 
size_t m_vertex_stride {}
 Bytes per vertex (stride for vertex buffer binding)
 
- Protected Attributes inherited from MayaFlux::Nodes::Node
std::vector< NodeHookm_callbacks
 Collection of standard callback functions.
 
std::vector< std::pair< NodeHook, NodeCondition > > m_conditional_callbacks
 Collection of conditional callback functions with their predicates.
 
uint32_t m_frame_rate { 60 }
 Frame rate for time-based processing, used for normalization.
 
bool m_gpu_compatible {}
 Flag indicating if the node supports GPU processing This flag is set by derived classes to indicate whether the node can be processed on the GPU.
 
std::vector< float > m_gpu_data_buffer
 GPU data buffer for context objects.
 
double m_last_output { 0 }
 The most recent sample value generated by this oscillator.
 
bool m_networked_node {}
 Flag indicating if the node is part of a NodeNetwork This flag is used to disable event firing when the node is managed within a NodeNetwork, preventing redundant or conflicting event notifications.
 
uint8_t m_node_capability { NodeCapability::SCALAR }
 Bitmask of capabilities declared by this node.
 
uint32_t m_sample_rate { 48000 }
 Sample rate for audio processing, used for normalization.
 
bool m_state_saved {}
 tracks if the node's state has been saved by a snapshot operation
 
uint32_t m_timing_rate { m_sample_rate }
 Current timing rate for the node, used for timing calculations (can be sample rate or frame rate)
 

Detailed Description

Generates dense vertex paths from sparse control points or freehand drawing.

Supports two distinct workflows:

  1. Parametric curve editing via control points (full regeneration on changes)
  2. Incremental freehand drawing (append-only strokes with smoothing on completion)

Both modes use Catmull-Rom or other interpolation methods to generate smooth curves. Produces LINE_STRIP topology output.

Philosophy:

  • Dual-mode design: parametric editing + incremental drawing in one node
  • Structural Reactivity: Only parametric paths (control points) are live. Changing interpolation modes, tension, or sampling density will rebuild the parametric curve but will NOT affect completed freehand strokes.
  • Control points are sparse input (artist/algorithm provides key positions)
  • Freehand strokes draw linearly in real-time, smooth on completion
  • Output vertices are dense (GPU draws smooth curves)
  • Interpolation happens CPU-side, leveraging Kinesis math primitives
  • Fixed memory allocation (real-time safe after construction)
  • Visual Reactivity: Changes to color and thickness are applied globally to both live control-point paths and "baked" freehand strokes.
  • Memory Efficiency: Freehand strokes are converted to static vertices upon completion; raw mouse data is discarded, preventing re-interpolation of baked strokes.

Parametric Mode Usage:

auto path = std::make_shared<PathGeneratorNode>(
32, // 32 vertices between each control point
100 // Store up to 100 control points
);
path->add_control_point({glm::vec3(0.0f, 0.0f, 0.0f)});
path->add_control_point({glm::vec3(0.5f, 0.5f, 0.0f)});
path->add_control_point({glm::vec3(1.0f, 0.0f, 0.0f)});
// Entire curve regenerates through all control points
auto buffer = std::make_shared<GeometryBuffer>(path);
buffer->setup_rendering({
.target_window = window,
.topology = PrimitiveTopology::LINE_STRIP
});

Freehand Drawing Mode Usage:

auto path = std::make_shared<PathGeneratorNode>(
32 // Smoothing resolution
);
// Real-time drawing (linear segments)
window->on_mouse_move([path](double x, double y) {
if (mouse_button_pressed) {
path->draw_to(screen_to_ndc(x, y)); // Appends linear segment
}
});
// Smooth the stroke when finished
window->on_mouse_release([path]() {
path->complete(); // Replaces linear segments with smooth curve
});
auto buffer = std::make_shared<GeometryBuffer>(path);
buffer->setup_rendering({.target_window = window});

Implementation Details:

  • Control points stored in fixed-capacity ring buffer (index [0] = newest)
  • Freehand strokes use sliding 4-point window for Catmull-Rom interpolation
  • Three vertex collections: control point geometry, completed strokes, in-progress stroke
  • Parametric edits trigger full regeneration; freehand is append-only
  • Both modes can coexist: control points and freehand strokes are independent

Definition at line 85 of file PathGeneratorNode.hpp.


The documentation for this class was generated from the following files: