Loading...
Searching...
No Matches
SceneDuplicator.hpp
1#pragma once
2#include <halp/controls.hpp>
3#include <halp/meta.hpp>
4
5#include <ossia/dataflow/geometry_port.hpp>
6
7#include <cstdint>
8#include <memory>
9#include <string>
10
11namespace Threedim
12{
13
14// Scene-graph-level duplicator: given a prototype scene_spec, emits N cloned
15// root nodes placed by a procedural pattern. Complementary to Instancer, which
16// does GPU-primitive instancing -- one mesh, N instances, one draw call, up to
17// a million particles from a single-mesh prototype. This one clones a rich
18// prototype with hierarchy, multiple meshes and lights into N CPU clones, each
19// with its own TRS, scaling to dozens or a few hundred.
20//
21// Materials, animations, skeletons and environment pass through from the
22// prototype unchanged and are shared across clones; only the root-level node
23// tree is cloned, so downstream path-based tooling addresses each clone
24// independently.
25//
26// Patterns: Grid lays `count` clones on an XZ grid with `spacing` at Y=0; Ring
27// puts them on a circle of `radius` in the XZ plane facing outward; Line runs
28// them along +X with `spacing` separation.
29//
30// Each clone's root node is named `<proto_name>_<idx>`, 0-indexed, so
31// SceneDuplicator(prototype=ChairScene, mode=Ring, count=8) yields /Chair_0 to
32// /Chair_7 and ConfigurePrimitive(paths=["/Chair_*"]) addresses them all.
34{
35public:
36 halp_meta(name, "Scene Duplicator")
37 halp_meta(category, "Visuals/3D/Scene")
38 halp_meta(c_name, "scene_duplicator")
39 halp_meta(description, "Clone a scene hierarchy into a grid, ring or line of independently transformed copies.")
40 halp_meta(authors, "ossia team")
41 halp_meta(
42 manual_url,
43 "https://ossia.io/score-docs/processes/scene-duplicator.html")
44 halp_meta(uuid, "9e7a4b3d-5f2c-4a8b-9d1e-6c3f8b5d2a7e")
45
46 enum Pattern
47 {
48 Grid,
49 Ring,
50 Line
51 };
52
53 struct ins
54 {
55 struct
56 {
57 halp_meta(name, "Scene In");
58 ossia::scene_spec scene;
59 uint8_t dirty{0};
60 } scene_in;
61
62 // Port-driven rebuild: controls trigger rebuild(); upstream
63 // scene_in changes detected in operator()().
64 struct : halp::combobox_t<"Pattern", Pattern>
65 {
66 struct range
67 {
68 std::string_view values[3]{"Grid", "Ring", "Line"};
69 int init{0};
70 };
71 void update(SceneDuplicator& n) { n.rebuild(); }
72 } pattern;
73
74 struct : halp::spinbox_i32<"Count", halp::irange{1, 4096, 4}>
75 { void update(SceneDuplicator& n) { n.rebuild(); } } count;
76 struct : halp::hslider_f32<"Spacing", halp::range{0.01, 1000., 2.}>
77 { void update(SceneDuplicator& n) { n.rebuild(); } } spacing;
78 struct : halp::hslider_f32<"Radius", halp::range{0.01, 1000., 5.}>
79 { void update(SceneDuplicator& n) { n.rebuild(); } } radius;
80 // Grid mode: grid is `cols × rows` with cols ≈ round(sqrt(count)).
81 // Exposed as a control so the user can force a specific aspect.
82 // 0 = auto (square-ish).
83 struct : halp::spinbox_i32<"Grid cols", halp::irange{0, 256, 0}>
84 { void update(SceneDuplicator& n) { n.rebuild(); } } grid_cols;
85 } inputs;
86
87 struct outs
88 {
89 struct
90 {
91 halp_meta(name, "Scene Out");
92 ossia::scene_spec scene;
93 uint8_t dirty{0};
94 } scene_out;
95 } outputs;
96
97 void rebuild();
98 void operator()();
99
100 // Stable shared_ptr cached while inputs are unchanged — keeps
101 // ScenePreprocessor's fingerprint fast-path warm.
102 std::shared_ptr<const ossia::scene_state> m_cached_out;
103 uint8_t m_pending_dirty{0xFF};
104 const ossia::scene_state* m_cached_in_state{};
105 int64_t m_cached_in_version{-1};
106 int64_t m_version_counter{0};
107};
108
109}
Definition SceneDuplicator.hpp:34
Definition SceneDuplicator.hpp:54
Definition SceneDuplicator.hpp:88
Definition MIDISync.hpp:128