| Line |
Branch |
Exec |
Source |
| 1 |
|
|
// SPDX-License-Identifier: BSD-3-Clause |
| 2 |
|
|
/// @file vol.cpp |
| 3 |
|
|
/// @brief Volumes' and fields' registry entries and extents: fields from their grids' headers, |
| 4 |
|
|
/// volumes from their fields. |
| 5 |
|
|
#include "ernie/scene/schema/vol.h" |
| 6 |
|
|
|
| 7 |
|
|
#include "ernie/io/nanovdb.h" |
| 8 |
|
|
|
| 9 |
|
|
#include <glm/glm.hpp> |
| 10 |
|
|
|
| 11 |
|
|
#include <stdexcept> |
| 12 |
|
|
#include <string> |
| 13 |
|
|
#include <vector> |
| 14 |
|
|
|
| 15 |
|
|
namespace ernie { |
| 16 |
|
|
namespace { |
| 17 |
|
|
|
| 18 |
|
|
/// @return The bounds of the grid a field selects by name and index from the headers `read` |
| 19 |
|
|
/// returns; empty when it has none, or its source is missing or unreadable (the renderer reports |
| 20 |
|
|
/// those). |
| 21 |
|
7 |
template <typename Read> Box SelectedGrid(const Read& read, std::string_view name, int index) { |
| 22 |
|
|
try { |
| 23 |
3/4
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 time.
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
7 |
const std::vector<NanoVdbGrid> heads = read(); |
| 24 |
2/4
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
6 |
const NanoVdbGrid* grid = FindNanoVdbGrid(heads, name, index); |
| 25 |
4/8
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
|
6 |
return grid != nullptr ? grid->GridBounds() : Box(); |
| 26 |
1/4
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
ernie::Box ernie::(anonymous namespace)::SelectedGrid<ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1}>(ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}::operator()(unsigned int) const::{lambda()#1} const&, std::basic_string_view<char, std::char_traits<char> >, int):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 |
} catch (const std::runtime_error&) { |
| 27 |
|
1 |
return {}; |
| 28 |
|
|
} |
| 29 |
|
|
} |
| 30 |
|
|
|
| 31 |
|
|
/// File fields from the file's grid headers, without reading voxels. |
| 32 |
|
6 |
void FileFieldExtent(const ExtentRows& rows, RowRange range, std::span<Box> out) { |
| 33 |
|
6 |
const auto path = rows.Column<Token>(FieldAsset::kFilePath); |
| 34 |
|
6 |
const auto name = rows.Column<Token>(FieldAsset::kFieldName); |
| 35 |
|
6 |
const auto index = rows.Column<std::int32_t>(FieldAsset::kFieldIndex); |
| 36 |
|
6 |
ComputeRows(range, out, [&](std::uint32_t row) { |
| 37 |
3/4
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 1 time.
|
18 |
return SelectedGrid([&] { return ReadNanoVdbHeads(std::string(rows.Text(path[row]))); }, |
| 38 |
|
6 |
rows.Text(name[row]), index[row]); |
| 39 |
|
|
}); |
| 40 |
|
6 |
} |
| 41 |
|
|
|
| 42 |
|
|
/// In-memory NanoVDB fields from their grids' headers; none for grids still on a device. |
| 43 |
|
1 |
void NanoVdbFieldExtent(const ExtentRows& rows, RowRange range, std::span<Box> out) { |
| 44 |
|
1 |
const auto buffer = rows.Column<Tensor>(NanoVDBField::kBuffer); |
| 45 |
|
1 |
const auto name = rows.Column<Token>(NanoVDBField::kFieldName); |
| 46 |
|
1 |
const auto index = rows.Column<std::int32_t>(NanoVDBField::kFieldIndex); |
| 47 |
|
1 |
ComputeRows(range, out, [&](std::uint32_t row) { |
| 48 |
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 |
const Tensor& grids = buffer[row]; |
| 49 |
3/6
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
|
1 |
if (grids.Empty() || !grids.OnHost() || !grids.IsContiguous()) { |
| 50 |
|
✗ |
return Box(); |
| 51 |
|
|
} |
| 52 |
|
1 |
const std::span<const std::uint8_t> bytes(static_cast<const std::uint8_t*>(grids.Data()), |
| 53 |
|
1 |
static_cast<std::size_t>(grids.Elements()) * |
| 54 |
|
1 |
ByteSize(grids.Type())); |
| 55 |
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
2 |
return SelectedGrid([&] { return ParseNanoVdbHeads(bytes); }, rows.Text(name[row]), |
| 56 |
|
1 |
index[row]); |
| 57 |
|
|
}); |
| 58 |
|
1 |
} |
| 59 |
|
|
|
| 60 |
|
|
/// Dense fields from their shape: values at the voxel size times their indices, grown by a voxel |
| 61 |
|
|
/// for what trilinear sampling reaches. |
| 62 |
|
1 |
void DenseFieldExtent(const ExtentRows& rows, RowRange range, std::span<Box> out) { |
| 63 |
|
1 |
const auto values = rows.Column<Tensor>(DenseField::kValues); |
| 64 |
|
1 |
const auto voxel = rows.Column<double>(DenseField::kVoxelSize); |
| 65 |
|
1 |
ComputeRows(range, out, [&](std::uint32_t row) { |
| 66 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 |
const Tensor& grid = values[row]; |
| 67 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 |
if (grid.Rank() != 3) { |
| 68 |
|
✗ |
return Box(); |
| 69 |
|
|
} |
| 70 |
|
1 |
const glm::dvec3 shape(grid.Shape()[0], grid.Shape()[1], grid.Shape()[2]); |
| 71 |
|
1 |
return Box{glm::dvec3(-voxel[row]), shape * voxel[row]}; |
| 72 |
|
|
}); |
| 73 |
|
1 |
} |
| 74 |
|
|
|
| 75 |
|
|
/// Volumes from their fields' extents, each brought into the volume's space. |
| 76 |
|
4 |
void VolumeExtent(const ExtentRows& rows, RowRange range, std::span<Box> out) { |
| 77 |
|
4 |
const Bucket& bucket = rows.store.GetBucket(rows.bucket); |
| 78 |
|
4 |
ComputeRows(range, out, [&](std::uint32_t row) { |
| 79 |
|
4 |
Box box; |
| 80 |
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
|
64 |
for (const Column& column : bucket.columns) { |
| 81 |
5/6
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
64 |
if (column.values->Type() != ColumnType::Relationship || !column.authored.Test(row) || |
| 82 |
|
4 |
!rows.Text(column.attribute).starts_with(tokens::kFieldPrefix)) { |
| 83 |
|
56 |
continue; |
| 84 |
|
|
} |
| 85 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
if (const std::optional<Box> extent = rows.TargetExtent( |
| 86 |
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 |
rows.store.Read<Target>(rows.bucket, column.attribute)[row], row)) { |
| 87 |
|
4 |
box.Extend(*extent); |
| 88 |
|
|
} |
| 89 |
|
|
} |
| 90 |
|
4 |
return box; |
| 91 |
|
|
}); |
| 92 |
|
4 |
} |
| 93 |
|
|
|
| 94 |
|
|
} // namespace |
| 95 |
|
|
|
| 96 |
|
2 |
Volume& Volume::SetField(std::string_view name, const Path& field) { |
| 97 |
3/6
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
8 |
Edit().Set(Id(), std::string(tokens::kFieldPrefix) + std::string(name), field); |
| 98 |
|
2 |
return *this; |
| 99 |
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 |
} |
| 100 |
|
|
|
| 101 |
5/8
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 146 times.
✗ Branch 10 not taken.
|
152 |
ERNIE_DEFINE_SCHEMA(Volume, Concrete, ComputedFromOtherPrims(VolumeExtent), ERNIE_NO_ATTRIBUTES, |
| 102 |
|
|
.openNamespaces = {tokens::kFieldPrefix}) |
| 103 |
4/6
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 438 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
|
584 |
ERNIE_DEFINE_SCHEMA(FieldBase, Abstract, kInheritExtent, ERNIE_NO_ATTRIBUTES) |
| 104 |
12/24
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 146 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 146 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 146 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 146 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 146 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 146 times.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 146 times.
✓ Branch 29 taken 730 times.
✓ Branch 30 taken 146 times.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
|
1752 |
ERNIE_DEFINE_SCHEMA(FieldAsset, Abstract, ComputedExtent(FileFieldExtent), |
| 105 |
|
|
ERNIE_FIELD_ASSET_ATTRIBUTES) |
| 106 |
9/16
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 146 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 146 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 146 times.
✓ Branch 19 taken 146 times.
✓ Branch 20 taken 146 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
|
446 |
ERNIE_DEFINE_SCHEMA(OpenVDBAsset, Concrete, kInheritExtent, ERNIE_OPENVDB_ASSET_ATTRIBUTES) |
| 107 |
8/16
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 146 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 146 times.
✓ Branch 18 taken 438 times.
✓ Branch 19 taken 146 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
|
1024 |
ERNIE_DEFINE_SCHEMA(NanoVDBField, Concrete, ComputedExtent(NanoVdbFieldExtent), |
| 108 |
|
|
ERNIE_NANOVDB_FIELD_ATTRIBUTES) |
| 109 |
8/16
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 146 times.
✗ Branch 10 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 146 times.
✓ Branch 18 taken 292 times.
✓ Branch 19 taken 146 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
|
732 |
ERNIE_DEFINE_SCHEMA(DenseField, Concrete, ComputedExtent(DenseFieldExtent), |
| 110 |
|
|
ERNIE_DENSE_FIELD_ATTRIBUTES) |
| 111 |
|
|
|
| 112 |
|
|
} // namespace ernie |
| 113 |
|
|
|