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
56{
57 if (m_count > 0 || !upstream)
58 return;
59
60 const auto data = upstream->get_vertex_data();
61 const auto layout = upstream->get_vertex_layout();
62 std::string type_name = upstream->get_vertex_type_name();
63
64 if (type_name == "PointVertex") {
66 } else if (type_name == "LineVertex") {
68 } else if (type_name == "MeshVertex") {
70 } else {
72 "FieldOperator::seed_from_upstream: unrecognized vertex type '{}', defaulting to LineVertex",
73 type_name);
75 }
76
77 if (data.empty() || layout.stride_bytes == 0)
78 return;
79
80 if (layout.stride_bytes != k_stride) {
82 "FieldOperator::seed_from_upstream: upstream stride {} != k_stride {}, skipping",
83 layout.stride_bytes, k_stride);
84 return;
85 }
86
87 const size_t count = data.size() / k_stride;
88 if (count == 0)
89 return;
90
91 store_reference(data.data(), count);
92
94 "FieldOperator seeded {} vertices from upstream '{}'",
95 count, upstream->get_type_name());
96}
97
98// =========================================================================
99// Processing
100// =========================================================================
101
103{
104 if (m_count == 0)
105 return;
106
108 std::memcpy(m_vertex_data.data(), m_reference_data.data(), m_count * k_stride);
109 }
110
111 bool has_position = !m_position_fields.empty();
112 bool has_color = !m_color_fields.empty();
113 bool has_normal = !m_normal_fields.empty();
114 bool has_tangent = !m_tangent_fields.empty();
115 bool has_scalar = !m_scalar_fields.empty();
116 bool has_uv = !m_uv_fields.empty();
117
118 for (size_t i = 0; i < m_count; ++i) {
119 glm::vec3& pos = vec3_at(i, k_position_offset);
120
121 if (has_position) {
122 glm::vec3 displacement(0.0F);
123 for (const auto& field : m_position_fields) {
124 displacement += field(pos);
125 }
126 pos += displacement;
127 }
128
129 if (has_color) {
130 glm::vec3 color(0.0F);
131 for (const auto& field : m_color_fields) {
132 color += field(pos);
133 }
134 vec3_at(i, k_color_offset) = color;
135 }
136
137 if (has_normal) {
138 glm::vec3 normal(0.0F);
139 for (const auto& field : m_normal_fields) {
140 normal += field(pos);
141 }
142 float len = glm::length(normal);
143 vec3_at(i, k_normal_offset) = len > 1e-6F ? normal / len : glm::vec3(0.0F, 0.0F, 1.0F);
144 }
145
146 if (has_tangent) {
147 glm::vec3 tangent(0.0F);
148 for (const auto& field : m_tangent_fields) {
149 tangent += field(pos);
150 }
151 float len = glm::length(tangent);
152 vec3_at(i, k_tangent_offset) = len > 1e-6F ? tangent / len : glm::vec3(1.0F, 0.0F, 0.0F);
153 }
154
155 if (has_scalar) {
156 float value = 0.0F;
157 for (const auto& field : m_scalar_fields) {
158 value += field(pos);
159 }
160 float_at(i, k_scalar_offset) = value;
161 }
162
163 if (has_uv) {
164 const glm::vec3 ref = ref_position_at(i);
165 glm::vec2 uv(0.0F);
166 for (const auto& field : m_uv_fields)
167 uv += field(ref);
168 *reinterpret_cast<glm::vec2*>(
169 m_vertex_data.data() + i * k_stride + k_uv_offset) = uv;
170 }
171 }
172
173 m_dirty = true;
174}
175
176// =========================================================================
177// Field binding
178// =========================================================================
179
181{
182 switch (target) {
184 m_position_fields.push_back(std::move(field));
185 break;
187 m_color_fields.push_back(std::move(field));
188 break;
190 m_normal_fields.push_back(std::move(field));
191 break;
193 m_tangent_fields.push_back(std::move(field));
194 break;
195 default:
197 "Cannot bind VectorField to scalar target {:d}",
198 static_cast<int>(target));
199 break;
200 }
201}
202
204{
205 switch (target) {
207 m_scalar_fields.push_back(std::move(field));
208 break;
209 case FieldTarget::UV:
211 "UV target requires a UVField, not a SpatialField. "
212 "Use bind(FieldTarget::UV, Kinesis::UVField) instead.");
213 break;
214 default:
216 "Cannot bind SpatialField to vector target {:d}",
217 static_cast<int>(target));
218 break;
219 }
220}
221
223{
224 if (target != FieldTarget::UV) {
226 "UVField can only be bound to FieldTarget::UV");
227 return;
228 }
229 m_uv_fields.push_back(std::move(field));
230}
231
233{
234 switch (target) {
236 m_position_fields.clear();
237 break;
239 m_color_fields.clear();
240 break;
242 m_normal_fields.clear();
243 break;
245 m_tangent_fields.clear();
246 break;
248 m_scalar_fields.clear();
249 break;
250 case FieldTarget::UV:
251 m_uv_fields.clear();
252 break;
253 }
254}
255
257{
258 m_position_fields.clear();
259 m_color_fields.clear();
260 m_normal_fields.clear();
261 m_tangent_fields.clear();
262 m_scalar_fields.clear();
263 m_uv_fields.clear();
264}
265
266// =========================================================================
267// Vertex accessors
268// =========================================================================
269
270glm::vec3& FieldOperator::vec3_at(size_t i, size_t offset)
271{
272 return *reinterpret_cast<glm::vec3*>(m_vertex_data.data() + i * k_stride + offset);
273}
274
275float& FieldOperator::float_at(size_t i, size_t offset)
276{
277 return *reinterpret_cast<float*>(m_vertex_data.data() + i * k_stride + offset);
278}
279
280glm::vec3 FieldOperator::ref_position_at(size_t i) const
281{
282 return *reinterpret_cast<const glm::vec3*>(m_reference_data.data() + i * k_stride + k_position_offset);
283}
284
285// =========================================================================
286// GraphicsOperator interface
287// =========================================================================
288
289std::span<const uint8_t> FieldOperator::get_vertex_data() const
290{
291 return { m_vertex_data.data(), m_vertex_data.size() };
292}
293
294std::span<const uint8_t> FieldOperator::get_vertex_data_for_collection(uint32_t) const
295{
296 return get_vertex_data();
297}
298
300{
302 switch (m_vertex_type) {
305 break;
306 case VertexType::LINE:
308 break;
309 case VertexType::MESH:
311 break;
312 default:
313 return {};
314 }
315 layout.vertex_count = static_cast<uint32_t>(m_count);
316 return layout;
317}
318
320{
321 return m_count;
322}
323
325{
326 return m_dirty;
327}
328
330{
331 m_dirty = false;
332}
333
335{
336 return m_count;
337}
338
340{
341 switch (m_vertex_type) {
343 return "PointVertex";
344 case VertexType::LINE:
345 return "LineVertex";
346 case VertexType::MESH:
347 return "MeshVertex";
348 default:
349 return "Unknown";
350 }
351}
352
353std::vector<PointVertex> FieldOperator::extract_point_vertices() const
354{
355 std::vector<PointVertex> result(m_count);
356 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
357 return result;
358}
359
360std::vector<LineVertex> FieldOperator::extract_line_vertices() const
361{
362 std::vector<LineVertex> result(m_count);
363 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
364 return result;
365}
366
367std::vector<MeshVertex> FieldOperator::extract_mesh_vertices() const
368{
369 std::vector<MeshVertex> result(m_count);
370 if (m_count > 0) {
371 std::memcpy(result.data(), m_vertex_data.data(), m_count * k_stride);
372 }
373 return result;
374}
375
376void FieldOperator::set_parameter(std::string_view param, double value)
377{
378 if (param == "mode") {
380 }
381}
382
383std::optional<double> FieldOperator::query_state(std::string_view query) const
384{
385 if (query == "point_count") {
386 return static_cast<double>(m_count);
387 }
388 if (query == "field_count") {
389 return static_cast<double>(
390 m_position_fields.size() + m_color_fields.size()
391 + m_normal_fields.size() + m_tangent_fields.size()
392 + m_scalar_fields.size() + m_uv_fields.size());
393 }
394 return std::nullopt;
395}
396
398 std::string_view param,
399 const std::shared_ptr<NodeNetwork>& source)
400{
402}
403
404void* FieldOperator::get_data_at(size_t global_index)
405{
406 if (global_index >= m_count)
407 return nullptr;
408 return m_vertex_data.data() + global_index * k_stride;
409}
410
411} // namespace MayaFlux::Nodes::Network
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
size_t count
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 seed_from_upstream(const GraphicsOperator *upstream) override
Seed vertex data from the upstream operator's current output.
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.
virtual Kakshya::VertexLayout get_vertex_layout() const =0
Get vertex layout describing vertex structure.
virtual std::span< const uint8_t > get_vertex_data() const =0
Get vertex data for GPU upload.
virtual const char * get_vertex_type_name() const =0
Get human-readable vertex type name (for validation/debugging)
Operator that produces GPU-renderable geometry.
virtual std::string_view get_type_name() const =0
Type name for introspection.
@ 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