MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshTransformOperator.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "MeshOperator.hpp"
4
6
7/**
8 * @class MeshTransformOperator
9 * @brief Primary operator that drives slot local transforms via Tendency fields
10 * and propagates world transforms down the slot DAG.
11 *
12 * Each slot may have at most one bound TemporalField (glm::mat4 -> glm::mat4).
13 * On process_slot() the field is evaluated with dt as the scalar input,
14 * converting it to a glm::vec3 (unused) placeholder -- in practice the mat4
15 * overload is used: the field receives the slot's current local_transform and
16 * returns the new local_transform for the cycle.
17 *
18 * Because transform propagation requires the parent's world_transform to
19 * already be resolved before a child is processed, process_slot() is called
20 * in topological order (guaranteed by MeshOperator::process()). Each call:
21 * 1. Evaluates the bound field (if any) to update local_transform.
22 * 2. Derives world_transform as parent_world * local_transform.
23 * 3. Sets slot.dirty = true so MeshNetworkProcessor triggers a re-upload.
24 *
25 * Slots without a bound field still receive world transform propagation --
26 * their local_transform is used as-is, matching the behaviour of the manual
27 * example in the fracture example (which drives local_transform and dirty
28 * directly without an operator).
29 *
30 * The TemporalField signature: glm::mat4 -> glm::mat4. In Kinesis terms
31 * this is modelled as a std::function<glm::mat4(float)> where the float
32 * argument is the accumulated time in seconds. The operator tracks per-slot
33 * accumulated time independently.
34 *
35 * Usage:
36 * @code
37 * auto xf_op = net->create_operator<MeshTransformOperator>();
38 *
39 * // rotate slot 0 around Y at 1 rad/s
40 * xf_op->bind(0, [](float t) {
41 * return glm::rotate(glm::mat4(1.0F), t, glm::vec3(0, 1, 0));
42 * });
43 * @endcode
44 */
45class MAYAFLUX_API MeshTransformOperator : public MeshOperator {
46public:
47 /**
48 * @brief Field type: maps accumulated time (seconds) to a local glm::mat4.
49 */
50 using TransformField = std::function<glm::mat4(float)>;
51
53 ~MeshTransformOperator() override = default;
54
55 // -------------------------------------------------------------------------
56 // Field binding
57 // -------------------------------------------------------------------------
58
59 /**
60 * @brief Bind a TransformField to a slot.
61 * @param slot_index Target slot index (as returned by MeshNetwork::add_slot()).
62 * @param field Function mapping accumulated time to local glm::mat4.
63 *
64 * Replaces any previously bound field for that slot.
65 * Pass an empty std::function to remove a binding.
66 */
67 void bind(uint32_t slot_index, TransformField field);
68
69 /**
70 * @brief Remove the TransformField bound to a slot.
71 * @param slot_index Target slot index.
72 */
73 void unbind(uint32_t slot_index);
74
75 /**
76 * @brief Remove all bound fields.
77 */
78 void unbind_all();
79
80 // -------------------------------------------------------------------------
81 // MeshOperator interface
82 // -------------------------------------------------------------------------
83
84 /**
85 * @brief Evaluate the bound field (if any), update local_transform, then
86 * propagate the world_transform from the parent.
87 */
88 void process_slot(MeshSlot& slot, float dt) override;
89
90 void process(float dt) override;
91
92 [[nodiscard]] std::string_view get_type_name() const override
93 {
94 return "MeshTransform";
95 }
96
97private:
98 std::unordered_map<uint32_t, TransformField> m_fields;
99
100 /**
101 * @brief Per-slot accumulated time in seconds, keyed by slot index.
102 */
103 std::unordered_map<uint32_t, float> m_accumulated_time;
104
105 /**
106 * @brief Wall-clock timestamp of the last process() call.
107 *
108 * Used to compute a real dt independent of the num_samples argument,
109 * which is always 1 for visual-rate networks and carries no time information.
110 */
111 std::chrono::steady_clock::time_point m_last_tick { std::chrono::steady_clock::now() };
112
113 /**
114 * @brief Resolve the world transform of a slot's parent, or identity if root.
115 * @param slot Slot whose parent_index is queried.
116 * @return Parent's world_transform, or identity mat4 for root slots.
117 */
118 [[nodiscard]] glm::mat4 parent_world(const MeshSlot& slot) const;
119};
120
121} // namespace MayaFlux::Nodes::Network
Abstract base for operators that process MeshNetwork slots.
std::string_view get_type_name() const override
Type name for introspection.
std::unordered_map< uint32_t, float > m_accumulated_time
Per-slot accumulated time in seconds, keyed by slot index.
std::unordered_map< uint32_t, TransformField > m_fields
std::function< glm::mat4(float)> TransformField
Field type: maps accumulated time (seconds) to a local glm::mat4.
Primary operator that drives slot local transforms via Tendency fields and propagates world transform...
Named, independently transformable mesh unit within a MeshNetwork.
Definition MeshSlot.hpp:31