GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
35 / 41
85.4%
Branches:
43 / 71
60.6%
Functions:
3 / 3, 6 excl
100.0%

scene/scene.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file scene.h
3 /// @brief The scene: typed prims at paths, stored in columns by type.
4 #pragma once
5
6 #include "ernie/export.h"
7 #include "ernie/geometry/bounds.h"
8 #include "ernie/scene/extent_cache.h"
9 #include "ernie/scene/holder_index.h"
10 #include "ernie/scene/schema.h"
11 #include "ernie/scene/storage.h"
12 #include "ernie/scene/time_samples.h"
13 #include "ernie/scene/value.h"
14
15 #include <glm/glm.hpp>
16
17 #include <map>
18 #include <optional>
19 #include <string>
20 #include <string_view>
21 #include <unordered_map>
22 #include <vector>
23
24 namespace ernie {
25
26 /// @brief Prims named by paths, each of a registered type, its attributes validated against the
27 /// type's schema and stored in the columns of the type's bucket.
28 class ERNIE_API Scene {
29 public:
30 Scene();
31 Scene(const Scene&) = delete;
32 Scene& operator=(const Scene&) = delete;
33
34 /// @brief Defines a prim of a concrete type, or `""` for none; missing ancestors are defined
35 /// without a type. Redefining with another type keeps the authored values both types declare.
36 /// @throws std::invalid_argument for the root, an empty path or an unknown or abstract type.
37 PrimId Define(const Path& path, std::string_view type);
38 /// @brief Removes a prim and its descendants.
39 /// @return Whether there was a prim.
40 bool Remove(const Path& path);
41
42 std::optional<PrimId> Find(const Path& path) const;
43 /// @throws std::invalid_argument if there is no prim at `path`.
44 PrimId Require(const Path& path) const;
45 48 bool Has(const Path& path) const {
46
13/19
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 1 time.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 time.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 1 time.
✗ Branch 18 not taken.
46 return Find(path).has_value();
47 }
48 Path PrimPath(PrimId prim) const;
49 /// @return The prim's type name; empty for none.
50 std::string_view TypeName(PrimId prim) const;
51 /// @return The prim's schema, or null for a prim without a type.
52 const SchemaDef* Schema(PrimId prim) const;
53 std::vector<Path> Children(const Path& path) const;
54 /// @return Every prim whose type is `type` or derives from it; every prim for `""`.
55 std::vector<Path> Prims(std::string_view type = {}) const;
56
57 /// @brief Applies an API schema, `"MaterialBindingAPI"`, or an instance of a multiple-apply
58 /// one, `"CollectionAPI:lights"`, adding its attributes at their fallbacks; one the prim has
59 /// already, built in or applied, is left as it is.
60 /// @throws std::invalid_argument for an unknown API schema or a missing or extra instance.
61 void ApplyApi(PrimId prim, std::string_view api);
62 /// @brief Removes an applied API schema with the values of its attributes.
63 /// @return Whether it was applied.
64 bool RemoveApi(PrimId prim, std::string_view api);
65 bool HasApi(PrimId prim, std::string_view api) const;
66 /// @return The applied API schemas, as `ApplyApi` names them.
67 std::vector<std::string> AppliedApis(PrimId prim) const;
68
69 /// @brief Authors an attribute: a declared one converted to its type and checked, or an
70 /// undeclared one, typed by its first value, in a namespace the type leaves open or on a prim
71 /// without a type.
72 /// @throws std::invalid_argument for a missing prim, an undeclared attribute or a bad value.
73 void Set(PrimId prim, std::string_view attribute, const Value& value);
74 void Set(const Path& path, std::string_view attribute, const Value& value);
75 /// @return The authored value, or none.
76 std::optional<Value> Get(PrimId prim, std::string_view attribute) const;
77 /// @brief `Get` by the attribute's token, for readers that look it up once.
78 std::optional<Value> Get(PrimId prim, AttributeId attribute) const;
79 /// @return The authored value, else the fallback its schema declares; none when neither.
80 std::optional<Value> GetOrFallback(PrimId prim, std::string_view attribute) const;
81 std::optional<Value> Get(const Path& path, std::string_view attribute) const;
82 /// @return An inherited attribute's value as of the last `Update`: the prim's own or its
83 /// nearest authoring ancestor's (where "inherited" isn't authoring), else the fallback; none
84 /// for a prim that isn't Imageable.
85 std::optional<Value> GetResolved(PrimId prim, std::string_view attribute) const;
86 /// @brief Authors an array attribute with a tensor on the host or a device, shared, not copied.
87 /// @throws std::invalid_argument for a non-array attribute, or a tensor of the wrong type or
88 /// shape.
89 void Write(PrimId prim, std::string_view attribute, Tensor array);
90 /// @return The authored array, or null.
91 const Tensor* Read(PrimId prim, std::string_view attribute) const;
92
93 /// @brief Sets the attribute's value at a time code, a time sample, as `UsdAttribute::Set`
94 /// with a time does. A sampled attribute holds its samples' value at `Time`, interpolated
95 /// between the samples either side and held beyond the ends; `Set` or `Write` without a time
96 /// drops its samples. An attribute's samples are all values or all arrays.
97 /// @throws std::invalid_argument as `Set` does.
98 void SetAt(PrimId prim, std::string_view attribute, double time, const Value& value);
99 /// @brief `SetAt` for an array, kept and shared as `Write` keeps one. Device arrays between
100 /// samples hold the lower one, for their consumers to mix on the device (`Samples`).
101 void WriteAt(PrimId prim, std::string_view attribute, double time, Tensor array);
102 /// @return The attribute's samples in time order; empty when it has none.
103 std::span<const TimeSample> Samples(PrimId prim, std::string_view attribute) const;
104 /// @return The attribute's value at `time` without moving the clock: its samples', else its
105 /// authored value; none when unset or an array.
106 std::optional<Value> GetAt(PrimId prim, std::string_view attribute, double time) const;
107 /// @brief Drops the attribute's samples, keeping the value it holds now.
108 /// @return Whether it had any.
109 bool ClearSamples(PrimId prim, std::string_view attribute);
110 /// @brief Moves the clock, evaluating every sampled attribute and stamping those whose value
111 /// changes.
112 void SetTime(double timeCode);
113 8 double Time() const {
114 8 return time_;
115 }
116 /// @brief Unauthors an attribute and drops its samples.
117 /// @return Whether the attribute was authored.
118 bool Clear(PrimId prim, std::string_view attribute);
119 bool IsAuthored(PrimId prim, std::string_view attribute) const;
120 /// @return The declaration of the prim's attribute by its type or API schemas, or null.
121 const AttributeDef* Declaration(PrimId prim, std::string_view attribute) const;
122 /// @return The authored attributes' names, in column order.
123 std::vector<std::string> Attributes(const Path& path) const;
124
125 /// @return The prim's own transform from its ops; identity for prims that aren't Xformable.
126 glm::dmat4 LocalTransform(PrimId prim) const;
127 glm::dmat4 WorldTransform(PrimId prim) const;
128 /// @return The prim's extent in its own space; none when it isn't computed from attributes.
129 /// Cached since `Update` when its bucket hasn't changed, computed otherwise.
130 std::optional<Box> Extent(PrimId prim) const;
131 /// @brief Brings derived data up to date with the edits since the last update, once per step
132 /// before renderers pull changes: resolves inherited attributes for the subtrees whose
133 /// authored values or prims changed, re-indexes changed relationships, then recomputes the
134 /// changed rows' cached extents.
135 void Update();
136 /// @return The prims whose relationships target `target` as of the last `Update`, resolved
137 /// material bindings included: what an edit to `target` reaches.
138 std::vector<PrimId> Holders(const Path& target) const;
139 /// @return The world box of the prim and its visible descendants of the default purpose.
140 /// Prims with extents bound their own subtrees, as UsdGeomBBoxCache prunes at Boundables.
141 Box WorldBounds(const Path& path) const;
142 /// @return The box of a prim's subtree in its parent's space, whatever its visibility: what a
143 /// point instancer places at each instance.
144 Box BoundsInParent(PrimId prim) const;
145
146 81 PrimStore& Store() {
147
9/18
<unknown function 146>:
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 10 taken 64 times.
✗ Branch 11 not taken.
<unknown function 45>:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 time.
✗ Branch 11 not taken.
79 return store_;
148 }
149 10682 const PrimStore& Store() const {
150
5/12
<unknown function 149>:
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1510 times.
✗ Branch 7 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
<unknown function 150>:
✓ Branch 1 taken 3358 times.
✗ Branch 2 not taken.
14120 return store_;
151 }
152 /// @return An id no other scene of this process has had, even one at the same address.
153 5 std::uint64_t Id() const {
154
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
5 return id_;
155 }
156 52 std::uint64_t Version() const {
157
7/12
<unknown function 146>:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
<unknown function 149>:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
<unknown function 45>:
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 13 times.
51 return store_.Version();
158 }
159 /// @return What a column change means to renderers: the attribute's declared category, or for
160 /// undeclared ones Transform for xformOps, Primvars for primvars and Params for the rest.
161 Dirty Classify(const ChangeSet::Values& change) const;
162
163 private:
164
2/2
✓ Branch 4 taken 482 times.
✓ Branch 5 taken 233 times.
4186 struct BucketSchema {
165 const SchemaDef* schema = nullptr;
166 std::unordered_map<AttributeId, const AttributeDef*> declared;
167 };
168
169 /// @return The bucket of a type and applied API schemas, made if new.
170 BucketId FindOrAddBucket(const SchemaDef* schema, std::vector<Token> apis);
171 /// Moves a prim to the bucket of its type and `apis`.
172 void MoveTo(PrimId prim, const SchemaDef* schema, std::vector<Token> apis);
173 const std::vector<Token>& Apis(PrimId prim) const;
174 /// @return A type's built-in API schemas, then the applied ones, each with those built into it,
175 /// each once.
176 std::vector<ApiName> AllApis(const SchemaDef* schema, std::span<const Token> applied) const;
177 /// @return The attribute's column when the prim authors it, or null.
178 const Column* AuthoredColumn(PrimId prim, std::string_view attribute) const;
179 const Column* AuthoredColumn(PrimId prim, AttributeId attribute) const;
180 /// @return The attribute's value when the prim authors it as a `T`, or null.
181 413 template <typename T> const T* Authored(PrimId prim, std::string_view attribute) const {
182 413 const std::optional<Token> token = store_.Tokens().Find(attribute);
183
5/6
ernie::Tensor const* ernie::Scene::Authored<ernie::Tensor>(ernie::PrimId, std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 263 times.
✗ Branch 1 not taken.
std::vector<float, std::allocator<float> > const* ernie::Scene::Authored<std::vector<float, std::allocator<float> > >(ernie::PrimId, std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
unsigned int const* ernie::Scene::Authored<unsigned int>(ernie::PrimId, std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 8 times.
413 return token ? store_.Get<T>(prim, *token) : nullptr;
184 }
185 std::optional<Value> CellValue(PrimId prim, const Column* column) const;
186 /// Checks a value against the attribute and authors it; with `checked`, converts it there
187 /// instead, as `Get` would return it.
188 void Author(PrimId prim, std::string_view attribute, const Value& value,
189 Value* checked = nullptr);
190 /// @throws std::invalid_argument if the attribute takes no such array.
191 void CheckArray(PrimId prim, std::string_view attribute, const Tensor& array) const;
192 /// Adds a checked sample, then authors the attribute's value at the clock.
193 void AddSample(PrimId prim, std::string_view attribute, TimeSample sample);
194 /// Authors a sampled attribute's value at the clock, if it changed.
195 void Evaluate(PrimId prim, AttributeId attribute, std::span<const TimeSample> samples);
196
197 /// Resolves every inherited attribute for the subtrees changed since the last resolve.
198 void Resolve();
199 const AttributeDef* Declared(BucketId bucket, AttributeId attribute) const;
200 /// @return Whether the prim's type or an applied API schema leaves the attribute's namespace
201 /// open; any attribute for a prim without a type.
202 bool TakesUndeclared(PrimId prim, std::string_view attribute) const;
203 /// @throws std::invalid_argument unless the prim takes the undeclared attribute.
204 void RequireUndeclared(PrimId prim, std::string_view attribute) const;
205 ColumnType TypeForUndeclared(PrimId prim, std::string_view attribute, const Value& value) const;
206 /// @return Whether the prim and its subtree are invisible or of a purpose bounds leave out.
207 bool LeavesOutOfBounds(PrimId prim) const;
208 /// @return GeomModelAPI's extentsHint: the default purpose's box, or with `allPurposes`, all.
209 Box ExtentsHint(PrimId prim, bool allPurposes) const;
210 /// Adds a subtree's extents under `parent`'s transform; with `visibleOnly`, only its visible
211 /// default-purpose prims'.
212 void AddTo(Box& bounds, PathId path, const glm::dmat4& parent, bool visibleOnly) const;
213
214 std::uint64_t id_;
215 PrimStore store_;
216 /// The store version inherited attributes were last resolved at.
217 std::uint64_t resolved_ = 0;
218 /// The sampled attributes of each prim, by its slot; sparse, as few attributes are animated.
219 11 struct Animated {
220 PrimId prim;
221 std::map<AttributeId, std::vector<TimeSample>> samples;
222 };
223 std::unordered_map<std::uint32_t, Animated> animated_;
224 double time_ = 0.0;
225 Token inherited_ = 0;
226 Token invisible_ = 0;
227 Token defaultPurpose_ = 0;
228 std::vector<BucketSchema> buckets_;
229 ExtentCache extents_;
230 HolderIndex holders_;
231 };
232
233 } // namespace ernie
234