MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FieldOperator.cpp
Go to the documentation of this file.
1#include "FieldOperator.hpp"
2
5
7
9 : m_mode(mode)
10{
11}
12
13// =========================================================================
14// Initialization
15// =========================================================================
16
17void FieldOperator::store_reference(const void* data, size_t count)
18{
19 m_count = count;
20 size_t total = count * k_stride;
21 m_reference_data.resize(total);
22 m_vertex_data.resize(total);
23 std::memcpy(m_reference_data.data(), data, total);
24 std::memcpy(m_vertex_data.data(), data, total);
25 m_dirty = true;
26}
27
28void FieldOperator::initialize(const std::vector<PointVertex>& vertices)
29{
31 store_reference(vertices.data(), vertices.size());
32
34 "FieldOperator initialized with {} PointVertex", vertices.size());
35}
36
37void FieldOperator::initialize(const std::vector<LineVertex>& vertices)
38{
40 store_reference(vertices.data(), vertices.size());
41
43 "FieldOperator initialized with {} LineVertex", vertices.size());
44}
45
46void FieldOperator::initialize(const std::vector<MeshVertex>& vertices)
47{
49 store_reference(vertices.data(), vertices.size());
50
52 "FieldOperator initialized with {} MeshVertex", vertices.size());
53}
54
55// =========================================================================
56// Processing
57// =========================================================================
58
60{
61 if (m_count == 0)
62 return;
63
65 std::memcpy(m_vertex_data.data(), m_reference_data.data(), m_count * k_stride);
66 }
67
68 bool has_position = !m_position_fields.empty();
69 bool has_color = !m_color_fields.empty();
70 bool has_normal = !m_normal_fields.empty();
71 bool has_tangent = !m_tangent_fields.empty();
72 bool has_scalar = !m_scalar_fields.empty();
73 bool has_uv = !m_uv_fields.empty();
74
75 for (size_t i = 0; i < m_count; ++i) {
76 glm::vec3& pos = vec3_at(i, k_position_offset);
77
78 if (has_position) {
79 glm::vec3 displacement(0.0F);
80 for (const auto& field : m_position_fields) {
81 displacement += field(pos);
82 }
83 pos += displacement;
84 }
85
86 if (has_color) {
87 glm::vec3 color(0.0F);
88 for (const auto& field : m_color_fields) {
89 color += field(pos);
90 }
92 }
93
94 if (has_normal) {
95 glm::vec3 normal(0.0F);
96 for (const auto& field : m_normal_fields) {
97 normal += field(pos);
98 }
99 float len = glm::length(normal);
100 vec3_at(i, k_normal_offset) = len > 1e-6F ? normal / len : glm::vec3(0.0F, 0.0F, 1.0F);
101 }
102
103 if (has_tangent) {
104 glm::vec3 tangent(0.0F);
105 for (const auto& field : m_tangent_fields) {
106 tangent += field(pos);
107 }
108 float len = glm::length(tangent);
109 vec3_at(i, k_tangent_offset) = len > 1e-6F ? tangent / len : glm::vec3(1.0F, 0.0F, 0.0F);
110 }
111
112 if (has_scalar) {
113 float value = 0.0F;
114 for (const auto& field : m_scalar_fields) {
115 value += field(pos);
116 }
117 float_at(i, k_scalar_offset) = value;
118 }
119
120 if (has_uv) {
121 const glm::vec3 ref = ref_position_at(i);
122 glm::vec2 uv(0.0F);
123 for (const auto& field : m_uv_fields)
124 uv += field(ref);
125 *reinterpret_cast<glm::vec2*>(
126 m_vertex_data.data() + i * k_stride + k_uv_offset) = uv;
127 }
128 }
129
130 m_dirty = true;
131}
132
133// =========================================================================
134// Field binding
135// =========================================================================
136
138{
139 switch (target) {
141 m_position_fields.push_back(std::move(field));
142 break;
144 m_color_fields.push_back(std::move(field));
145 break;
147 m_normal_fields.push_back(std::move(field));
148 break;
150 m_tangent_fields.push_back(std::move(field));
151 break;
152 default:
154 "Cannot bind VectorField to scalar target {:d}",
155 static_cast<int>(target));
156 break;
157 }
158}
159
161{
162 switch (target) {
164 m_scalar_fields.push_back(std::move(field));
165 break;
166 case FieldTarget::UV:
168 "UV target requires a UVField, not a SpatialField. "
169 "Use bind(FieldTarget::UV, Kinesis::UVField) instead.");
170 break;
171 default:
173 "Cannot bind SpatialField to vector target {:d}",
174 static_cast<int>(target));
175 break;
176 }
177}
178
180{
181 if (target != FieldTarget::UV) {
183 "UVField can only be bound to FieldTarget::UV");
184 return;
185 }
186 m_uv_fields.push_back(std::move(field));
187}
188
190{
191 switch (target) {
193 m_position_fields.clear();
194 break;
196 m_color_fields.clear();
197 break;
199 m_normal_fields.clear();
200 break;
202 m_tangent_fields.clear();
203 break;
205 m_scalar_fields.clear();
206 break;
207 case FieldTarget::UV:
208 m_uv_fields.clear();
209 break;
210 }
211}
212
214{
215 m_position_fields.clear();
216 m_color_fields.clear();
217 m_normal_fields.clear();
218 m_tangent_fields.clear();
219 m_scalar_fields.clear();
220 m_uv_fields.clear();
221}
222
223// =========================================================================
224// Vertex accessors
225// =========================================================================
226
227glm::vec3& FieldOperator::vec3_at(size_t i, size_t offset)
228{
229 return *reinterpret_cast<glm::vec3*>(m_vertex_data.data() + i * k_stride + offset);
230}
231
232float& FieldOperator::float_at(size_t i, size_t offset)
233{
234 return *reinterpret_cast<float*>(m_vertex_data.data() + i * k_stride + offset);
235}
236
237glm::vec3 FieldOperator::ref_position_at(size_t i) const
238{
239 return *reinterpret_cast<const glm::vec3*>(m_reference_data.data() + i * k_stride + k_position_offset);
240}
241
242// =========================================================================
243// GraphicsOperator interface
244// =========================================================================
245
246std::span<const uint8_t> FieldOperator::get_vertex_data() const
247{
248 return { m_vertex_data.data(), m_vertex_data.size() };
249}
250
251std::span<const uint8_t> FieldOperator::get_vertex_data_for_collection(uint32_t) const
252{
253 return get_vertex_data();
254}
255
257{
259 switch (m_vertex_type) {
262 break;
263 case VertexType::LINE:
265 break;
266 case VertexType::MESH:
268 break;
269 default:
270 return {};
271 }
272 layout.vertex_count = static_cast<uint32_t>(m_count);
273 return layout;
274}
275
277{
278 return m_count;
279}
280
282{
283 return m_dirty;
284}
285
287{
288 m_dirty = false;
289}
290
292{
293 return m_count;
294}
295
297{
298 switch (m_vertex_type) {
300 return "PointVertex";
301 case VertexType::LINE:
302 return "LineVertex";
303 case VertexType::MESH:
304 return "MeshVertex";
305 default:
306 return "Unknown";
307 }
308}
309
310std::vector<PointVertex> FieldOperator::extract_point_vertices() const
311{
312 std::vector<PointVertex> result(m_count);
313 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
314 return result;
315}
316
317std::vector<LineVertex> FieldOperator::extract_line_vertices() const
318{
319 std::vector<LineVertex> result(m_count);
320 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
321 return result;
322}
323
324std::vector<MeshVertex> FieldOperator::extract_mesh_vertices() const
325{
326 std::vector<MeshVertex> result(m_count);
327 if (m_count > 0) {
328 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
329 }
330 return result;
331}
332
333void FieldOperator::set_parameter(std::string_view param, double value)
334{
335 if (param == "mode") {
337 }
338}
339
340std::optional<double> FieldOperator::query_state(std::string_view query) const
341{
342 if (query == "point_count") {
343 return static_cast<double>(m_count);
344 }
345 if (query == "field_count") {
346 return static_cast<double>(
347 m_position_fields.size() + m_color_fields.size()
348 + m_normal_fields.size() + m_tangent_fields.size()
349 + m_scalar_fields.size() + m_uv_fields.size());
350 }
351 return std::nullopt;
352}
353
355 std::string_view param,
356 const std::shared_ptr<NodeNetwork>& source)
357{
359}
360
361void* FieldOperator::get_data_at(size_t global_index)
362{
363 if (global_index >= m_count)
364 return nullptr;
365 return m_vertex_data.data() + global_index * k_stride;
366}
367
368} // namespace MayaFlux::Nodes::Network
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
Eigen::Index count
std::optional< glm::vec3 > color
size_t get_point_count() const override
Get source point count (before topology expansion)
void store_reference(const void *data, size_t count)
std::vector< Kinesis::VectorField > m_position_fields
size_t get_vertex_count() const override
Get number of vertices (may differ from point count for topology/path)
void set_parameter(std::string_view param, double value) override
Set operator parameter.
bool is_vertex_data_dirty() const override
Check if geometry changed this frame.
void unbind_all()
Remove all bound fields.
std::vector< LineVertex > extract_line_vertices() const
std::vector< Kinesis::VectorField > m_tangent_fields
std::vector< Kinesis::SpatialField > m_scalar_fields
glm::vec3 & vec3_at(size_t i, size_t offset)
std::vector< Kinesis::VectorField > m_color_fields
Kakshya::VertexLayout get_vertex_layout() const override
Get vertex layout describing vertex structure.
std::span< const uint8_t > get_vertex_data_for_collection(uint32_t idx) const override
Get vertex data for specific collection (if multiple)
std::span< const uint8_t > get_vertex_data() const override
Get vertex data for GPU upload.
void * get_data_at(size_t global_index) override
Get mutable access to point at global index.
std::vector< PointVertex > extract_point_vertices() const
void mark_vertex_data_clean() override
Clear dirty flag after GPU upload.
void unbind(FieldTarget target)
Remove all fields bound to a target.
void apply_one_to_one(std::string_view param, const std::shared_ptr< NodeNetwork > &source) override
Apply ONE_TO_ONE parameter mapping (per-point control)
std::vector< Kinesis::VectorField > m_normal_fields
std::optional< double > query_state(std::string_view query) const override
Query operator internal state.
void bind(FieldTarget target, Kinesis::VectorField field)
Bind a VectorField to a vec3 target.
float & float_at(size_t i, size_t offset)
std::vector< Kinesis::UVField > m_uv_fields
const char * get_vertex_type_name() const override
Get human-readable vertex type name (for validation/debugging)
std::vector< MeshVertex > extract_mesh_vertices() const
void process(float dt) override
Process for one batch cycle.
void initialize(const std::vector< PointVertex > &vertices)
Initialize from PointVertex data.
FieldOperator(FieldMode mode=FieldMode::ABSOLUTE)
glm::vec3 ref_position_at(size_t i) const
void apply_one_to_one(std::string_view param, const std::shared_ptr< NodeNetwork > &source) override
Apply ONE_TO_ONE parameter mapping.
@ NodeProcessing
Node graph processing (Nodes::NodeGraphManager)
@ Nodes
DSP Generator and Filter Nodes, graph pipeline, node management.
FieldMode
How fields are applied each frame.
FieldTarget
Vertex attribute targets for Tendency field evaluation.
uint32_t vertex_count
Total number of vertices in this buffer.
static VertexLayout for_lines(uint32_t stride=60)
Factory: layout for LineVertex (position, color, thickness, uv, normal, tangent)
static VertexLayout for_meshes(uint32_t stride=60)
Factory: layout for MeshVertex (position, color, weight, uv, normal, tangent)
static VertexLayout for_points(uint32_t stride=60)
Factory: layout for PointVertex (position, color, size, uv, normal, tangent)
Complete description of vertex data layout in a buffer.
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22