MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshFieldOperator.cpp
Go to the documentation of this file.
2
5
7
8// =============================================================================
9// Private helpers
10// =============================================================================
11
12std::shared_ptr<FieldOperator>
13MeshFieldOperator::get_or_create(MeshSlot& slot, uint32_t slot_index)
14{
15 auto it = m_field_ops.find(slot_index);
16 if (it != m_field_ops.end())
17 return it->second;
18
19 auto op = std::make_shared<FieldOperator>(FieldMode::ABSOLUTE);
20
21 if (slot.node) {
22 op->initialize(slot.node->get_mesh_vertices());
24 "MeshFieldOperator: initialised FieldOperator for slot {} ({} vertices)",
25 slot_index, slot.node->get_mesh_vertex_count());
26 } else {
28 "MeshFieldOperator: slot {} has no node at bind time -- "
29 "FieldOperator initialised with empty vertex data",
30 slot_index);
31 }
32
33 m_field_ops.emplace(slot_index, op);
34 return op;
35}
36
37// =============================================================================
38// Field binding
39// =============================================================================
40
42 uint32_t slot_index, FieldTarget target, Kinesis::VectorField field)
43{
44 if (!m_slots) {
46 "MeshFieldOperator::bind called before set_slots() -- "
47 "FieldOperator will be initialised lazily on first process()");
48 }
49
50 if (m_slots) {
51 if (slot_index >= m_slots->size()) {
53 "MeshFieldOperator::bind: slot_index {} out of range ({})",
54 slot_index, m_slots->size());
55 return;
56 }
57 auto op = get_or_create((*m_slots)[slot_index], slot_index);
58 op->bind(target, std::move(field));
59 } else {
60 auto& op = m_field_ops[slot_index];
61 if (!op)
62 op = std::make_shared<FieldOperator>(FieldMode::ABSOLUTE);
63 op->bind(target, std::move(field));
64 }
65}
66
68 uint32_t slot_index, FieldTarget target, Kinesis::SpatialField field)
69{
70 if (m_slots && slot_index < m_slots->size()) {
71 get_or_create((*m_slots)[slot_index], slot_index)->bind(target, std::move(field));
72 } else {
73 auto& op = m_field_ops[slot_index];
74 if (!op)
75 op = std::make_shared<FieldOperator>(FieldMode::ABSOLUTE);
76 op->bind(target, std::move(field));
77 }
78}
79
81 uint32_t slot_index, FieldTarget target, Kinesis::UVField field)
82{
83 if (m_slots && slot_index < m_slots->size()) {
84 get_or_create((*m_slots)[slot_index], slot_index)->bind(target, std::move(field));
85 } else {
86 auto& op = m_field_ops[slot_index];
87 if (!op)
88 op = std::make_shared<FieldOperator>(FieldMode::ABSOLUTE);
89 op->bind(target, std::move(field));
90 }
91}
92
93void MeshFieldOperator::unbind(uint32_t slot_index, FieldTarget target)
94{
95 auto it = m_field_ops.find(slot_index);
96 if (it != m_field_ops.end())
97 it->second->unbind(target);
98}
99
100void MeshFieldOperator::unbind_slot(uint32_t slot_index)
101{
102 m_field_ops.erase(slot_index);
103}
104
106{
107 m_field_ops.clear();
108}
109
110void MeshFieldOperator::set_mode(uint32_t slot_index, FieldMode mode)
111{
112 auto it = m_field_ops.find(slot_index);
113 if (it != m_field_ops.end())
114 it->second->set_mode(mode);
115}
116
118 std::shared_ptr<Yantra::ShaderExecutionContext<>> executor, bool continuous)
119{
120 if (!executor) {
121 m_compute_node.reset();
122 m_executor.reset();
124 return;
125 }
126
128 if (m_slots) {
129 m_gpu_slot_vertex_counts.reserve(m_slots->size());
130 for (const auto& slot : *m_slots) {
131 m_gpu_slot_vertex_counts.push_back(
132 slot.node ? slot.node->get_mesh_vertex_count() : 0);
133 }
134 }
135
136 m_executor = std::move(executor);
137 m_compute_node = std::make_shared<Nodes::GpuSync::GpuComputeNode>(m_executor, continuous);
138
139 m_compute_node->on_complete([this](Nodes::GpuSync::GpuComputeContext& ctx) {
140 if (!m_slots)
141 return;
142
143 const auto& primary = ctx.gpu_result.primary;
144 constexpr size_t floats_per_vertex = sizeof(MeshVertex) / sizeof(float);
145
146 size_t offset = 0;
147 for (size_t i = 0; i < m_slots->size(); ++i) {
148 if (i >= m_gpu_slot_vertex_counts.size())
149 break;
150
151 const size_t vc = m_gpu_slot_vertex_counts[i];
152 const size_t float_count = vc * floats_per_vertex;
153
154 if (offset + float_count > primary.size())
155 break;
156
157 auto& slot = (*m_slots)[i];
158 if (!slot.node) {
159 offset += float_count;
160 continue;
161 }
162
163 std::vector<MeshVertex> verts(vc);
164 std::memcpy(verts.data(), primary.data() + offset,
165 float_count * sizeof(float));
166 slot.node->set_mesh_vertices(std::move(verts));
167
168 offset += float_count;
169 }
170 });
171
172 m_compute_node->set_dirty();
173}
174
175// =============================================================================
176// MeshOperator interface
177// =============================================================================
178
180{
181 auto it = m_field_ops.find(slot.index);
182 if (it == m_field_ops.end())
183 return;
184
185 auto& field_op = it->second;
186
187 if (field_op->get_vertex_count() == 0 && slot.node
188 && slot.node->get_mesh_vertex_count() > 0) {
189 field_op->initialize(slot.node->get_mesh_vertices());
191 "MeshFieldOperator: lazy-initialised slot {} ({} vertices)",
192 slot.index, slot.node->get_mesh_vertex_count());
193 }
194
195 field_op->process(dt);
196
197 if (field_op->is_vertex_data_dirty() && slot.node) {
198 slot.node->set_mesh_vertices(field_op->extract_mesh_vertices());
199 field_op->mark_vertex_data_clean();
200 }
201}
202
204{
205 if (m_compute_node) {
206 m_compute_node->compute_frame();
207 return;
208 }
209
211}
212
213} // namespace MayaFlux::Nodes::Network
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
const Yantra::GpuChannelResult & gpu_result
Reference to the full dispatch result. Valid during callback only.
Context delivered to on_complete callbacks when a dispatch completes.
std::unordered_map< uint32_t, std::shared_ptr< FieldOperator > > m_field_ops
std::shared_ptr< Yantra::ShaderExecutionContext<> > m_executor
void bind(uint32_t slot_index, FieldTarget target, Kinesis::VectorField field)
Bind a VectorField to a slot.
void set_mode(uint32_t slot_index, FieldMode mode)
Set the field application mode for a slot's FieldOperator.
std::shared_ptr< FieldOperator > get_or_create(MeshSlot &slot, uint32_t slot_index)
Return an existing FieldOperator for the slot, or create and initialise one from the slot's current v...
void unbind_slot(uint32_t slot_index)
Remove the entire FieldOperator for a slot.
std::vector< size_t > m_gpu_slot_vertex_counts
Vertex count per slot index, snapshotted at set_gpu_executor() time.
void unbind(uint32_t slot_index, FieldTarget target)
Remove all fields bound to a target on a specific slot.
std::shared_ptr< Nodes::GpuSync::GpuComputeNode > m_compute_node
void process(float dt) override
Process for one batch cycle.
void process_slot(MeshSlot &slot, float dt) override
Run the slot's FieldOperator (if bound) and write results back to slot.node via set_mesh_vertices().
void unbind_all()
Remove all per-slot FieldOperators.
void set_gpu_executor(std::shared_ptr< Yantra::ShaderExecutionContext<> > executor, bool continuous=true)
Attach a GPU executor and switch to async dispatch mode.
void process(float dt) override
Iterate slots in topological order and call process_slot() on each.
std::vector< MeshSlot > * m_slots
Concrete GpuExecutionContext for a single fixed shader with fixed bindings.
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
Tendency< glm::vec3, glm::vec2 > UVField
Definition Tendency.hpp:48
FieldMode
How fields are applied each frame.
FieldTarget
Vertex attribute targets for Tendency field evaluation.
Kakshya::MeshVertex MeshVertex
Definition VertexSpec.hpp:9
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
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
Named, independently transformable mesh unit within a MeshNetwork.
Definition MeshSlot.hpp:31