MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshNetwork.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "MeshSlot.hpp"
4#include "NodeNetwork.hpp"
5
7
8/**
9 * @class MeshNetwork
10 * @brief NodeNetwork subclass whose nodes are named, hierarchically
11 * transformable mesh slots.
12 *
13 * Each slot holds a MeshWriterNode (geometry) and a local-space glm::mat4.
14 * Slots form an optional DAG via parent indices; MeshNetwork resolves
15 * processing order so parents are always updated before children.
16 * World transforms propagate as: world = parent_world * local.
17 *
18 * The primary operator (set via create_operator<T> / set_operator) runs
19 * first each cycle. The operator chain (get_operator_chain()) runs after.
20 * Both receive the slot list via the operator interface.
21 *
22 * MeshNetwork initializes m_operator_chain on construction because it
23 * requires multi-operator sequencing as a necessity, not an option.
24 *
25 * No topology enum from NodeNetwork is used: the DAG is explicit via
26 * parent indices in each MeshSlot.
27 *
28 * Usage:
29 * @code
30 * auto net = std::make_shared<MeshNetwork>();
31 *
32 * auto torso_node = std::make_shared<GpuSync::MeshWriterNode>();
33 * torso_node->set_mesh(torso_verts, torso_indices);
34 * uint32_t torso = net->add_slot("torso", torso_node);
35 *
36 * auto arm_node = std::make_shared<GpuSync::MeshWriterNode>();
37 * arm_node->set_mesh(arm_verts, arm_indices);
38 * uint32_t arm_l = net->add_slot("arm_l", arm_node, torso);
39 *
40 * net->create_operator<MeshTransformOperator>();
41 * net->get_operator_chain()->emplace<MeshFieldOperator>();
42 * @endcode
43 */
44class MAYAFLUX_API MeshNetwork : public NodeNetwork {
45public:
47 ~MeshNetwork() override = default;
48
49 // -------------------------------------------------------------------------
50 // Slot management
51 // -------------------------------------------------------------------------
52
53 /**
54 * @brief Add a slot to the network.
55 * @param name Logical name for lookup and logging.
56 * @param node MeshWriterNode carrying the slot's geometry.
57 * @param parent Index of the parent slot, or nullopt for a root slot.
58 * @return Stable index of the new slot. Never changes after insertion.
59 */
60 uint32_t add_slot(
61 std::string name,
62 std::shared_ptr<GpuSync::MeshWriterNode> node,
63 std::optional<uint32_t> parent = std::nullopt);
64
65 /**
66 * @brief Return the slot at the given index.
67 * @param index Slot index as returned by add_slot().
68 */
69 [[nodiscard]] MeshSlot& get_slot(uint32_t index);
70 [[nodiscard]] const MeshSlot& get_slot(uint32_t index) const;
71
72 /**
73 * @brief Find a slot by name.
74 * @return Pointer to the slot, or nullptr if not found.
75 */
76 [[nodiscard]] MeshSlot* find_slot(std::string_view name);
77 [[nodiscard]] const MeshSlot* find_slot(std::string_view name) const;
78
79 /**
80 * @brief Find the index of a slot by name.
81 * @return Index, or nullopt if not found.
82 */
83 [[nodiscard]] std::optional<uint32_t> find_slot_index(std::string_view name) const;
84
85 /**
86 * @brief Number of slots in the network.
87 */
88 [[nodiscard]] size_t slot_count() const { return m_slots.size(); }
89
90 /**
91 * @brief Read-only access to the full slot list.
92 */
93 [[nodiscard]] const std::vector<MeshSlot>& slots() const { return m_slots; }
94 [[nodiscard]] std::vector<MeshSlot>& slots() { return m_slots; }
95
96 /**
97 * @brief Every slot's geometry merged into one MeshData, one submesh per slot.
98 *
99 * Slots with no node or no geometry are skipped. Each submesh is named for
100 * its slot, or by its index when the slot is unnamed, and its indices are
101 * offset into the shared vertex array. Vertices are in each slot's local
102 * space: no slot or world transform is applied.
103 *
104 * @return The merged mesh, or nullopt when no slot has geometry.
105 */
106 [[nodiscard]] std::optional<Kakshya::MeshData> get_mesh_data() const;
107
108 // -------------------------------------------------------------------------
109 // NodeNetwork interface
110 // -------------------------------------------------------------------------
111
112 void process_batch(unsigned int num_samples) override;
113 void reset() override;
114
115 [[nodiscard]] size_t get_node_count() const override { return m_slots.size(); }
116 [[nodiscard]] std::optional<double> get_node_output(size_t index) const override;
117 [[nodiscard]] std::unordered_map<std::string, std::string> get_metadata() const override;
118
119 // -------------------------------------------------------------------------
120 // Operator management (mirrors ParticleNetwork pattern)
121 // -------------------------------------------------------------------------
122
123 /**
124 * @brief Replace the primary operator.
125 * @param op New operator. Must be non-null.
126 */
127 void set_operator(std::shared_ptr<NetworkOperator> op);
128
129 /**
130 * @brief Construct and set the primary operator in one call.
131 * @tparam OpType Concrete operator type.
132 * @return Shared pointer to the new operator.
133 */
134 template <typename OpType, typename... Args>
135 std::shared_ptr<OpType> create_operator(Args&&... args)
136 {
137 auto op = std::make_shared<OpType>(std::forward<Args>(args)...);
138 set_operator(op);
139 return op;
140 }
141
143 {
144 return m_operator.get();
145 }
146
147 const NetworkOperator* get_operator() const override
148 {
149 return m_operator.get();
150 }
151
152 bool has_operator() const override
153 {
154 return m_operator != nullptr;
155 }
156
157 /**
158 * @brief Get the processing order of slots as indices into m_slots.
159 * Parents always appear before children.
160 */
161 [[nodiscard]] const std::vector<uint32_t>& sorted_indices() const { return m_sorted_indices; }
162
163 /**
164 * @brief Ensure the slot processing order is up to date. Called internally
165 * before processing, but can be called manually after making changes
166 * to the slot DAG.
167 */
168 void ensure_sorted();
169
170private:
171 std::vector<MeshSlot> m_slots;
172
173 /// @brief Processing order: indices into m_slots, parents before children.
174 std::vector<uint32_t> m_sorted_indices;
175
176 /// @brief Set when add_slot() changes the DAG and a re-sort is needed.
177 bool m_sort_dirty { true };
178
179 std::shared_ptr<NetworkOperator> m_operator;
180
181 void rebuild_sort();
182 void propagate_world_transforms();
183};
184
185} // namespace MayaFlux::Nodes::Network
std::vector< uint32_t > parent
std::string name
Definition VKDevice.cpp:123
uint32_t index
Definition VKDevice.cpp:122
std::vector< uint32_t > m_sorted_indices
Processing order: indices into m_slots, parents before children.
size_t get_node_count() const override
Get the number of nodes in the network.
size_t slot_count() const
Number of slots in the network.
std::shared_ptr< NetworkOperator > m_operator
NetworkOperator * get_operator() override
const std::vector< MeshSlot > & slots() const
Read-only access to the full slot list.
std::vector< MeshSlot > & slots()
const std::vector< uint32_t > & sorted_indices() const
Get the processing order of slots as indices into m_slots.
std::shared_ptr< OpType > create_operator(Args &&... args)
Construct and set the primary operator in one call.
const NetworkOperator * get_operator() const override
NodeNetwork subclass whose nodes are named, hierarchically transformable mesh slots.
Domain-agnostic interpretive lens for network processing.
Abstract base class for structured collections of nodes with defined relationships.
Named, independently transformable mesh unit within a MeshNetwork.
Definition MeshSlot.hpp:31