MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
InstanceFieldOperator.hpp
Go to the documentation of this file.
1#pragma once
2
4
6
8
10
11/**
12 * @class InstanceFieldOperator
13 * @brief Drives GeometrySlot transforms from stateless Kinesis fields.
14 *
15 * Each slot may have at most one PositionField or one TransformField bound,
16 * keyed by slot index. On each cycle the bound field is evaluated against the
17 * slot's current state and the result is written back into slot.transform.
18 *
19 * PositionField receives the slot's current translation (column 3 of
20 * slot.transform as glm::vec3) and returns a new translation. Only column 3
21 * is replaced; the rotational part of the matrix is preserved.
22 *
23 * TransformField receives the slot's current transform as glm::mat4 and
24 * returns a replacement mat4. The full matrix is replaced.
25 *
26 * Both field types are evaluated statelessly - no accumulated time, no
27 * internal integration. The field is a pure function of current slot state.
28 * For time-varying behaviour, close over a shared atomic or external clock in
29 * the field callable.
30 *
31 * Slots without a bound field are untouched.
32 */
33class MAYAFLUX_API InstanceFieldOperator : public InstanceOperator {
34public:
35 using TransformField = std::function<glm::mat4(const glm::mat4&)>;
37
38 /**
39 * @brief Bind a TransformField to a slot.
40 * @param slot_index Target slot index.
41 * @param field Function mapping current slot.transform to a new mat4.
42 *
43 * Replaces any previously bound field (position or transform) for the slot.
44 */
45 void bind_transform(uint32_t slot_index, TransformField field);
46
47 /**
48 * @brief Bind a PositionField to a slot.
49 * @param slot_index Target slot index.
50 * @param field VectorField mapping current slot translation to a new translation.
51 *
52 * Replaces any previously bound field (position or transform) for the slot.
53 */
54 void bind_position(uint32_t slot_index, PositionField field);
55
56 /**
57 * @brief Remove all bindings for a slot.
58 * @param slot_index Target slot index.
59 */
60 void unbind(uint32_t slot_index);
61
62 /**
63 * @brief Remove all bindings for all slots.
64 */
65 void unbind_all();
66
67 void process_slot(GeometrySlot& slot, float dt) override;
68
69 [[nodiscard]] std::string_view get_type_name() const override { return "InstanceField"; }
70
71 /**
72 * @brief Attach a GPU executor and switch to async dispatch mode.
73 *
74 * Constructs a GpuComputeNode from the executor. On each process() call
75 * the node's compute_frame() is driven instead of the CPU field loop.
76 * The on_complete callback reads gpu_result.primary as tightly-packed
77 * mat4 rows (16 floats per slot, in slot-index order) and writes into
78 * m_slots directly.
79 *
80 * CPU field bindings are preserved but ignored while a GPU executor is
81 * attached. Passing nullptr clears the GPU path and restores CPU evaluation.
82 *
83 * @param executor Pre-configured ShaderExecutionContext. Output binding must
84 * be sized for slot_count * 16 * sizeof(float). nullptr clears.
85 * @param continuous If true the node re-arms after every completed dispatch.
86 */
87 void set_gpu_executor(
88 std::shared_ptr<Yantra::ShaderExecutionContext<>> executor,
89 bool continuous = true);
90
91 /**
92 * @brief Update push constants on the attached GPU executor.
93 *
94 * Arms the next dispatch by calling set_dirty() after the push. No-op if
95 * no GPU executor is attached.
96 *
97 * @tparam T Trivially copyable struct matching the shader push constant layout.
98 * @param data Push constant data.
99 */
100 template <typename T>
101 void push_constants(const T& data)
102 {
103 if (m_executor)
104 m_executor->push(data);
105 if (m_compute_node)
106 m_compute_node->set_dirty();
107 }
108
109 /**
110 * @brief Returns true if a GPU executor is currently attached.
111 */
112 [[nodiscard]] bool has_gpu_executor() const { return m_compute_node != nullptr; }
113
114 // Override process() to drive compute_frame() on the GPU path.
115 void process(float dt) override;
116
117private:
118 std::unordered_map<uint32_t, TransformField> m_transform_fields;
119 std::unordered_map<uint32_t, PositionField> m_position_fields;
120
121 std::shared_ptr<Yantra::ShaderExecutionContext<>> m_executor;
122 std::shared_ptr<Nodes::GpuSync::GpuComputeNode> m_compute_node;
123};
124
125} // namespace MayaFlux::Nodes::Network
bool has_gpu_executor() const
Returns true if a GPU executor is currently attached.
std::shared_ptr< Nodes::GpuSync::GpuComputeNode > m_compute_node
std::string_view get_type_name() const override
Type name for introspection.
void push_constants(const T &data)
Update push constants on the attached GPU executor.
std::function< glm::mat4(const glm::mat4 &)> TransformField
std::unordered_map< uint32_t, PositionField > m_position_fields
std::shared_ptr< Yantra::ShaderExecutionContext<> > m_executor
std::unordered_map< uint32_t, TransformField > m_transform_fields
Drives GeometrySlot transforms from stateless Kinesis fields.
Abstract base for operators that process InstanceNetwork slots.
Concrete GpuExecutionContext for a single fixed shader with fixed bindings.
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
Peer unit within an InstanceNetwork.