MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshNetwork.cpp
Go to the documentation of this file.
1#include "MeshNetwork.hpp"
2
5
7
8// =============================================================================
9// Construction
10// =============================================================================
11
18
19// =============================================================================
20// Slot management
21// =============================================================================
22
24 std::string name,
25 std::shared_ptr<GpuSync::MeshWriterNode> node,
26 std::optional<uint32_t> parent)
27{
28 if (!node) {
29 error<std::invalid_argument>(
31 std::source_location::current(),
32 "MeshNetwork::add_slot: null MeshWriterNode for slot '{}'", name);
33 }
34
35 if (parent.has_value() && parent.value() >= m_slots.size()) {
36 error<std::out_of_range>(
38 std::source_location::current(),
39 "MeshNetwork::add_slot: parent index {} out of range (slot count: {})",
40 parent.value(), m_slots.size());
41 }
42
43 const auto idx = static_cast<uint32_t>(m_slots.size());
44
45 MeshSlot slot;
46 slot.index = idx;
47 slot.name = std::move(name);
48 slot.node = std::move(node);
49 slot.parent_index = parent;
50 slot.dirty = true;
51
52 if (parent.has_value()) {
53 m_slots[parent.value()].child_indices.push_back(idx);
54 }
55
56 m_slots.push_back(std::move(slot));
57 m_sort_dirty = true;
58
60 "MeshNetwork: added slot '{}' at index {} (parent: {})",
61 m_slots[idx].name, idx,
62 parent.has_value() ? std::to_string(parent.value()) : "none");
63
64 return idx;
65}
66
68{
69 return m_slots.at(index);
70}
71
72const MeshSlot& MeshNetwork::get_slot(uint32_t index) const
73{
74 return m_slots.at(index);
75}
76
77MeshSlot* MeshNetwork::find_slot(std::string_view name)
78{
79 auto it = std::ranges::find_if(m_slots,
80 [name](const MeshSlot& s) { return s.name == name; });
81 return it != m_slots.end() ? &*it : nullptr;
82}
83
84const MeshSlot* MeshNetwork::find_slot(std::string_view name) const
85{
86 auto it = std::ranges::find_if(m_slots,
87 [name](const MeshSlot& s) { return s.name == name; });
88 return it != m_slots.end() ? &*it : nullptr;
89}
90
91std::optional<uint32_t> MeshNetwork::find_slot_index(std::string_view name) const
92{
93 for (uint32_t i = 0; i < static_cast<uint32_t>(m_slots.size()); ++i) {
94 if (m_slots[i].name == name)
95 return i;
96 }
97 return std::nullopt;
98}
99
100// =============================================================================
101// NodeNetwork interface
102// =============================================================================
103
104void MeshNetwork::process_batch(unsigned int num_samples)
105{
106 if (!is_enabled() || m_slots.empty())
107 return;
108
109 if (m_sort_dirty)
110 rebuild_sort();
111
112 for (unsigned int frame = 0; frame < num_samples; ++frame) {
113 if (m_operator) {
114 if (auto* mesh_op = dynamic_cast<MeshOperator*>(m_operator.get()))
115 mesh_op->set_slots(m_slots, m_sorted_indices);
116 m_operator->process(static_cast<float>(frame));
117 } else {
119 }
120
121 if (m_operator_chain) {
122 for (const auto& op : m_operator_chain->operators()) {
123 if (auto* mesh_op = dynamic_cast<MeshOperator*>(op.get()))
124 mesh_op->set_slots(m_slots, m_sorted_indices);
125 op->process(static_cast<float>(frame));
126 }
127 }
128 }
129
130 for (const auto& slot : m_slots) {
131 if (slot.node)
132 slot.node->compute_frame();
133 }
134}
135
137{
138 for (auto& slot : m_slots) {
139 slot.local_transform = glm::mat4(1.0F);
140 slot.world_transform = glm::mat4(1.0F);
141 slot.dirty = true;
142 }
143}
144
145std::optional<double> MeshNetwork::get_node_output(size_t index) const
146{
147 if (index >= m_slots.size())
148 return std::nullopt;
149 return static_cast<double>(index);
150}
151
152std::unordered_map<std::string, std::string> MeshNetwork::get_metadata() const
153{
154 auto meta = NodeNetwork::get_metadata();
155 meta["slot_count"] = std::to_string(m_slots.size());
156 meta["operator"] = m_operator ? std::string(m_operator->get_type_name()) : "none";
157 meta["chain_size"] = m_operator_chain
158 ? std::to_string(m_operator_chain->size())
159 : "0";
160 return meta;
161}
162
163// =============================================================================
164// Operator management
165// =============================================================================
166
167void MeshNetwork::set_operator(std::shared_ptr<NetworkOperator> op)
168{
169 if (!op) {
171 "MeshNetwork::set_operator: null operator ignored");
172 return;
173 }
174 m_operator = std::move(op);
175}
176
178{
179 if (m_sort_dirty)
180 rebuild_sort();
181}
182
183// =============================================================================
184// Private helpers
185// =============================================================================
186
188{
189 // Kahn's algorithm: process roots first, then children.
190 std::vector<uint32_t> in_degree(m_slots.size(), 0);
191 for (const auto& slot : m_slots) {
192 if (slot.parent_index.has_value())
193 ++in_degree[slot.parent_index.value()];
194 }
195
196 // Roots: slots with no parent.
197 std::vector<uint32_t> queue;
198 for (uint32_t i = 0; i < static_cast<uint32_t>(m_slots.size()); ++i) {
199 if (!m_slots[i].parent_index.has_value())
200 queue.push_back(i);
201 }
202
203 m_sorted_indices.clear();
204 m_sorted_indices.reserve(m_slots.size());
205
206 while (!queue.empty()) {
207 uint32_t idx = queue.front();
208 queue.erase(queue.begin());
209 m_sorted_indices.push_back(idx);
210
211 for (uint32_t child : m_slots[idx].child_indices)
212 queue.push_back(child);
213 }
214
215 if (m_sorted_indices.size() != m_slots.size()) {
217 "MeshNetwork: slot DAG contains a cycle — sort is incomplete");
218 }
219
220 m_sort_dirty = false;
221
223 "MeshNetwork: rebuilt slot sort order ({} slots)", m_sorted_indices.size());
224}
225
227{
228 for (uint32_t idx : m_sorted_indices) {
229 auto& slot = m_slots[idx];
230 if (slot.parent_index.has_value()) {
231 slot.world_transform
232 = m_slots[slot.parent_index.value()].world_transform
233 * slot.local_transform;
234 } else {
235 slot.world_transform = slot.local_transform;
236 }
237 }
238}
239
240} // namespace MayaFlux::Nodes::Network
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
MeshSlot & get_slot(uint32_t index)
Return the slot at the given index.
std::vector< uint32_t > m_sorted_indices
Processing order: indices into m_slots, parents before children.
bool m_sort_dirty
Set when add_slot() changes the DAG and a re-sort is needed.
void set_operator(std::shared_ptr< NetworkOperator > op)
Replace the primary operator.
std::unordered_map< std::string, std::string > get_metadata() const override
Get network metadata for debugging/visualization.
uint32_t add_slot(std::string name, std::shared_ptr< GpuSync::MeshWriterNode > node, std::optional< uint32_t > parent=std::nullopt)
Add a slot to the network.
std::shared_ptr< NetworkOperator > m_operator
void process_batch(unsigned int num_samples) override
Process the network for the given number of samples.
void ensure_sorted()
Ensure the slot processing order is up to date.
std::optional< uint32_t > find_slot_index(std::string_view name) const
Find the index of a slot by name.
MeshSlot * find_slot(std::string_view name)
Find a slot by name.
std::optional< double > get_node_output(size_t index) const override
Get output of specific internal node (for ONE_TO_ONE mapping)
void reset() override
Reset network to initial state.
Abstract base for operators that process MeshNetwork slots.
virtual void set_topology(Topology topology)
Set the network's topology.
bool is_enabled() const
Check if network is enabled.
std::shared_ptr< OperatorChain > m_operator_chain
virtual std::unordered_map< std::string, std::string > get_metadata() const
Get network metadata for debugging/visualization.
void set_output_mode(OutputMode mode)
Set the network's output routing mode.
@ Init
Engine/subsystem initialization.
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
@ CUSTOM
User-defined arbitrary topology.
@ GRAPHICS_BIND
State available for visualization (read-only)
std::string name
Logical name. Used for lookup and logging only.
Definition MeshSlot.hpp:36
bool dirty
Set when local_transform or slot config changes since last upload.
Definition MeshSlot.hpp:54
std::shared_ptr< GpuSync::MeshWriterNode > node
Geometry node for this slot.
Definition MeshSlot.hpp:39
uint32_t index
Position of this slot in MeshNetwork::m_slots. Stable after insertion.
Definition MeshSlot.hpp:33
std::optional< uint32_t > parent_index
Index of the parent slot, or nullopt for a root slot.
Definition MeshSlot.hpp:48
Named, independently transformable mesh unit within a MeshNetwork.
Definition MeshSlot.hpp:31