Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
scene_node.hpp
Go to the documentation of this file.
1// SceneNode — abstract base of Pulp's retained vector scene graph.
2//
3// License-lineage note: the Pulp scene-graph primitives use Pulp-native
4// names (`VectorScene`, `SceneNode`, `ScenePath`, `SceneShape`,
5// `SceneImage`, `SceneText`, `SceneGroup`) rather than any reference
6// framework's class names. The design is derived from Skia's
7// SVG rendering literature plus what custom-paint widgets actually need
8// (mutate a sub-tree → re-paint only its bounding box), not from any
9// single C++ framework's headers.
10#pragma once
11
13
14#include <cstdint>
15#include <string>
16
17namespace pulp::canvas {
18
19class SceneGroup; // fwd-decl for parent pointer
20
27struct SceneRect {
28 float x = 0.0f;
29 float y = 0.0f;
30 float w = 0.0f;
31 float h = 0.0f;
32
33 constexpr bool empty() const { return w <= 0.0f || h <= 0.0f; }
34
36 constexpr SceneRect united(const SceneRect& other) const {
37 if (empty()) return other;
38 if (other.empty()) return *this;
39 const float minx = x < other.x ? x : other.x;
40 const float miny = y < other.y ? y : other.y;
41 const float maxx = (x + w) > (other.x + other.w) ? (x + w) : (other.x + other.w);
42 const float maxy = (y + h) > (other.y + other.h) ? (y + h) : (other.y + other.h);
43 return {minx, miny, maxx - minx, maxy - miny};
44 }
45
46 constexpr bool operator==(const SceneRect& o) const {
47 return x == o.x && y == o.y && w == o.w && h == o.h;
48 }
49 constexpr bool operator!=(const SceneRect& o) const { return !(*this == o); }
50};
51
57 float a = 1.0f, b = 0.0f;
58 float c = 0.0f, d = 1.0f;
59 float e = 0.0f, f = 0.0f;
60
61 static constexpr SceneTransform identity() { return {}; }
62 static constexpr SceneTransform translation(float tx, float ty) {
63 return {1, 0, 0, 1, tx, ty};
64 }
65
66 constexpr bool is_identity() const {
67 return a == 1.0f && b == 0.0f && c == 0.0f && d == 1.0f && e == 0.0f && f == 0.0f;
68 }
69
72 constexpr SceneTransform composed_with(const SceneTransform& r) const {
73 return {
74 a * r.a + c * r.b,
75 b * r.a + d * r.b,
76 a * r.c + c * r.d,
77 b * r.c + d * r.d,
78 a * r.e + c * r.f + e,
79 b * r.e + d * r.f + f,
80 };
81 }
82
86 SceneRect map_rect(const SceneRect& r) const;
87};
88
98
107public:
108 explicit SceneNode(SceneNodeKind kind) : kind_(kind) {}
109 virtual ~SceneNode() = default;
110
111 SceneNode(const SceneNode&) = delete;
112 SceneNode& operator=(const SceneNode&) = delete;
113
114 SceneNodeKind kind() const { return kind_; }
115
116 // ── Identity (debugging / SVG `<g id="...">` round-trip) ───────────
117 const std::string& id() const { return id_; }
118 void set_id(std::string v) { id_ = std::move(v); /* identity-only, no dirty */ }
119
120 // ── Visibility ───────────────────────────────────────────────────────
121 bool visible() const { return visible_; }
122 void set_visible(bool v) {
123 if (visible_ == v) return;
124 visible_ = v;
125 mark_dirty();
126 }
127
128 // ── Opacity ──────────────────────────────────────────────────────────
129 float opacity() const { return opacity_; }
130 void set_opacity(float a) {
131 if (opacity_ == a) return;
132 opacity_ = a;
133 mark_dirty();
134 }
135
136 // ── Transform ────────────────────────────────────────────────────────
137 const SceneTransform& transform() const { return transform_; }
139 if (transform_.a == t.a && transform_.b == t.b &&
140 transform_.c == t.c && transform_.d == t.d &&
141 transform_.e == t.e && transform_.f == t.f) return;
142 transform_ = t;
143 mark_dirty();
144 }
145
146 // ── Parent linkage (set by SceneGroup) ───────────────────────────────
147 SceneGroup* parent() const { return parent_; }
148
149 // ── Bounds ───────────────────────────────────────────────────────────
152 virtual SceneRect local_bounds() const = 0;
153
156 return transform_.map_rect(local_bounds());
157 }
158
159 // ── Paint ────────────────────────────────────────────────────────────
164 virtual void paint_geometry(Canvas& canvas) const = 0;
165
166 // ── Dirty tracking ───────────────────────────────────────────────────
167 bool dirty() const { return dirty_; }
168
174
178 void mark_clean(const SceneRect& painted_scene_bounds) {
179 dirty_ = false;
180 last_painted_bounds_ = painted_scene_bounds;
181 }
182
187 const SceneRect& last_painted_bounds() const { return last_painted_bounds_; }
188
189protected:
190 friend class SceneGroup; // sets parent_ during add_child()
191
192private:
193 SceneNodeKind kind_;
194 std::string id_;
195 SceneGroup* parent_ = nullptr;
196 SceneTransform transform_{};
197 float opacity_ = 1.0f;
198 bool visible_ = true;
199 bool dirty_ = true;
200 SceneRect last_painted_bounds_{};
201};
202
203} // namespace pulp::canvas
Definition canvas.hpp:240
Definition scene_group.hpp:18
bool dirty() const
Definition scene_node.hpp:167
friend class SceneGroup
Definition scene_node.hpp:190
void mark_dirty()
Mark this node and (recursively) every ancestor dirty.
SceneNodeKind kind() const
Definition scene_node.hpp:114
const SceneTransform & transform() const
Definition scene_node.hpp:137
void set_transform(const SceneTransform &t)
Definition scene_node.hpp:138
const std::string & id() const
Definition scene_node.hpp:117
SceneNode & operator=(const SceneNode &)=delete
virtual SceneRect local_bounds() const =0
Local-coordinate bounding box (pre-transform, pre-opacity).
float opacity() const
Definition scene_node.hpp:129
virtual ~SceneNode()=default
const SceneRect & last_painted_bounds() const
The scene-space rect this node occupied at the last paint.
Definition scene_node.hpp:187
SceneNode(const SceneNode &)=delete
SceneRect transformed_local_bounds() const
Bounds after the node's own transform — used for parent group unions.
Definition scene_node.hpp:155
void set_id(std::string v)
Definition scene_node.hpp:118
void set_opacity(float a)
Definition scene_node.hpp:130
SceneNode(SceneNodeKind kind)
Definition scene_node.hpp:108
void mark_clean(const SceneRect &painted_scene_bounds)
Called by the scene walker after a full paint.
Definition scene_node.hpp:178
void set_visible(bool v)
Definition scene_node.hpp:122
SceneGroup * parent() const
Definition scene_node.hpp:147
virtual void paint_geometry(Canvas &canvas) const =0
Paint this node (and its sub-tree) into canvas.
bool visible() const
Definition scene_node.hpp:121
Definition affine_transform.hpp:24
SceneNodeKind
Kind discriminator — keeps dynamic_cast off the hot path.
Definition scene_node.hpp:91
@ text
Definition scene_node.hpp:96
@ image
Definition scene_node.hpp:95
@ shape
Definition scene_node.hpp:94
@ path
Definition scene_node.hpp:93
@ group
Definition scene_node.hpp:92
Axis-aligned bounding box used for repaint-rect math.
Definition scene_node.hpp:27
float y
Definition scene_node.hpp:29
float h
Definition scene_node.hpp:31
constexpr bool operator!=(const SceneRect &o) const
Definition scene_node.hpp:49
float w
Definition scene_node.hpp:30
constexpr bool operator==(const SceneRect &o) const
Definition scene_node.hpp:46
constexpr bool empty() const
Definition scene_node.hpp:33
constexpr SceneRect united(const SceneRect &other) const
Union with other, treating empty rects as "no contribution".
Definition scene_node.hpp:36
float x
Definition scene_node.hpp:28
2D affine transform (CanvasRenderingContext2D layout): [ a c e ] [ b d f ] [ 0 0 1 ]
Definition scene_node.hpp:56
float d
Definition scene_node.hpp:58
float c
Definition scene_node.hpp:58
float b
Definition scene_node.hpp:57
static constexpr SceneTransform identity()
Definition scene_node.hpp:61
SceneRect map_rect(const SceneRect &r) const
Transform an axis-aligned rect — returns the AABB of the four transformed corners.
constexpr SceneTransform composed_with(const SceneTransform &r) const
Multiply (this * rhs).
Definition scene_node.hpp:72
float e
Definition scene_node.hpp:59
static constexpr SceneTransform translation(float tx, float ty)
Definition scene_node.hpp:62
constexpr bool is_identity() const
Definition scene_node.hpp:66
float a
Definition scene_node.hpp:57
float f
Definition scene_node.hpp:59