GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
55 / 59
93.2%
Branches:
37 / 52
71.2%
Functions:
8 / 8
100.0%

scene/animation.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file animation.cpp
3 /// @brief Time-sampled attributes: their sparse samples per prim, and the clock that evaluates
4 /// them into the columns.
5 #include "ernie/scene/scene.h"
6
7 #include <algorithm>
8
9 namespace ernie {
10
11 19 void Scene::SetAt(PrimId prim, std::string_view attribute, double time, const Value& value) {
12 19 TimeSample sample{time, {}, {}};
13
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 time.
19 Author(prim, attribute, value, &sample.value);
14
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
37 AddSample(prim, attribute, std::move(sample));
15 18 }
16
17 7 void Scene::WriteAt(PrimId prim, std::string_view attribute, double time, Tensor array) {
18 7 CheckArray(prim, attribute, array);
19
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 AddSample(prim, attribute, {time, {}, std::move(array)});
20 12 }
21
22 24 void Scene::AddSample(PrimId prim, std::string_view attribute, TimeSample sample) {
23 24 const AttributeId token = store_.Tokens().Intern(attribute);
24 24 Animated& animated = animated_[prim.slot];
25 24 animated.prim = prim;
26 24 std::vector<TimeSample>& samples = animated.samples[token];
27 // Samples are all values or all arrays: one of the other kind replaces them.
28
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
24 if (!samples.empty() && samples.front().tensor.Empty() != sample.tensor.Empty()) {
29 ✗ samples.clear();
30 }
31 24 const auto at = std::ranges::lower_bound(samples, sample.time, {}, &TimeSample::time);
32
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if (at != samples.end() && at->time == sample.time) {
33 ✗ *at = std::move(sample);
34 } else {
35 24 samples.insert(at, std::move(sample));
36 }
37 24 Evaluate(prim, token, samples);
38 24 }
39
40 5231 std::span<const TimeSample> Scene::Samples(PrimId prim, std::string_view attribute) const {
41 5231 const auto animated = animated_.find(prim.slot);
42 5231 const std::optional<Token> token = store_.Tokens().Find(attribute);
43
5/6
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 5179 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 7 times.
5335 if (animated == animated_.end() || animated->second.prim != prim || !token) {
44 5186 return {};
45 }
46 45 const auto samples = animated->second.samples.find(*token);
47
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 11 times.
90 return samples == animated->second.samples.end() ? std::span<const TimeSample>()
48 45 : std::span(samples->second);
49 }
50
51 1 std::optional<Value> Scene::GetAt(PrimId prim, std::string_view attribute, double time) const {
52 1 const std::span<const TimeSample> samples = Samples(prim, attribute);
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (samples.empty()) {
54 ✗ return Get(prim, attribute);
55 }
56 2 Value value = ernie::Evaluate(samples, time).value;
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
2 return value.Empty() ? std::nullopt : std::optional(std::move(value));
58 1 }
59
60 5002 bool Scene::ClearSamples(PrimId prim, std::string_view attribute) {
61
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5001 times.
5002 if (Samples(prim, attribute).empty()) {
62 return false;
63 }
64 1 const auto animated = animated_.find(prim.slot);
65 1 animated->second.samples.erase(*store_.Tokens().Find(attribute));
66
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (animated->second.samples.empty()) {
67 ✗ animated_.erase(animated);
68 }
69 return true;
70 }
71
72 5 void Scene::SetTime(double timeCode) {
73 5 time_ = timeCode;
74
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
15 for (const auto& [slot, animated] : animated_) {
75
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 5 times.
14 for (const auto& [attribute, samples] : animated.samples) {
76 9 Evaluate(animated.prim, attribute, samples);
77 }
78 }
79 5 }
80
81 33 void Scene::Evaluate(PrimId prim, AttributeId attribute, std::span<const TimeSample> samples) {
82 33 const std::string_view name = store_.Tokens().Text(attribute);
83 33 TimeSample now = ernie::Evaluate(samples, time_);
84
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 26 times.
33 if (!now.tensor.Empty()) {
85
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 const Tensor* current = Read(prim, name);
86
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 3 times.
7 if (current == nullptr || current->Data() != now.tensor.Data()) {
87
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 store_.Set(prim, attribute, std::move(now.tensor));
88 }
89
4/6
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 16 times.
26 } else if (Get(prim, name) != now.value) {
90
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 Author(prim, name, now.value);
91 }
92 33 }
93
94 } // namespace ernie
95