载入中...
搜索中...
未找到
VegetationSceneLiveElements.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cctype>
5#include <cmath>
6#include <limits>
7#include <new>
8#include <numeric>
9#include <set>
10#include <string_view>
11
12namespace eve::asset_graphics {
13namespace {
14bool finite(float value) { return std::isfinite(value); }
15
16bool validGuid(std::string_view value, bool allowEmpty) {
17 return (allowEmpty && value.empty()) ||
18 (value.size() == 32 && std::all_of(value.begin(), value.end(), [](unsigned char character) {
19 return std::isxdigit(character) != 0;
20 }));
21}
22
23bool validElement(const VegetationSceneElement& element) {
24 static const std::set<std::string> kinds{
25 "color-effect", "color-map", "color-noise", "color-tint", "extras-alpha", "extras-emissive",
26 "extras-overlay", "extras-wetness", "motion-advanced", "motion-interaction", "motion-wind-power",
27 "vertex-conform-model", "vertex-conform-simple", "vertex-conform-terrain", "vertex-height-offset",
28 "vertex-height", "vertex-orientation-model", "vertex-orientation-terrain", "vertex-size"};
29 const std::uint32_t expectedChannel = element.kind.starts_with("color-") ? 0u
30 : element.kind.starts_with("extras-") ? 1u
31 : element.kind.starts_with("motion-") ? 2u
32 : 3u;
33 const float rotationLength = std::sqrt(std::inner_product(element.rotation.begin(), element.rotation.end(),
34 element.rotation.begin(), 0.f));
35 std::set<std::string> propertyNames;
36 const auto finiteValues = [](const auto& values) {
37 return std::all_of(values.begin(), values.end(), [](float value) { return finite(value); });
38 };
39 if (element.sourceFileId == 0 || !validGuid(element.shaderGuid, false) ||
40 !validGuid(element.textureGuid, true) || !kinds.contains(element.kind) || element.channel != expectedChannel ||
41 (element.visibility != -1 && element.visibility != 0 && element.visibility != 10 &&
42 element.visibility != 20) ||
43 element.layers == 0 || (element.layers & ~0x1ffu) || !finite(element.intensity) || element.intensity < 0.f ||
44 element.intensity > 1.f || !finite(element.motionPower) || element.motionPower < 0.f ||
45 element.motionPower > 1.f || !finiteValues(element.position) || !finiteValues(element.rotation) ||
46 !finiteValues(element.scale) || !finiteValues(element.value) || !finiteValues(element.remap) ||
47 !finiteValues(element.seasons[0]) || !finiteValues(element.seasons[1]) ||
48 !finiteValues(element.seasons[2]) || !finiteValues(element.seasons[3]) ||
49 std::abs(rotationLength - 1.f) > 1e-3f ||
50 std::any_of(element.scale.begin(), element.scale.end(), [](float value) { return value <= 0.f; }) ||
51 element.remap[0] > element.remap[1] || element.remap[2] > element.remap[3] ||
52 element.remap[4] > element.remap[5] || element.blendRgb < 0 || element.blendRgb > 2 ||
53 element.blendAlpha < 0 || element.blendAlpha > 1 ||
54 (element.directionMode != 10 && element.directionMode != 20 && element.directionMode != 30 &&
55 element.directionMode != 40) ||
56 (element.motionMode != 13 && element.motionMode != 15) || element.properties.size() > 256 ||
57 (!element.textureAsset.empty() && !AssetRef::parse(element.textureAsset)))
58 return false;
59 for (const auto& property : element.properties) {
60 if (property.name.empty() || property.name.size() > 128 || property.type < 0 || property.type > 2 ||
61 !validGuid(property.textureGuid, true) ||
62 !finiteValues(property.vector) || !finite(property.value) ||
63 (!property.textureAsset.empty() && !AssetRef::parse(property.textureAsset)) ||
64 !propertyNames.emplace(property.name).second)
65 return false;
66 }
67 return true;
68}
69} // namespace
70
72 LoadedVegetationScene baseScene, std::uint64_t owner) {
73 if (owner == 0 || baseScene.elements.size() > 4096)
75 DiagnosticCode::InvalidArgument, "vegetation live-element registry identity or scene is invalid", {}, {},
76 "asset.graphics.vegetation-live-elements"));
77 if (std::any_of(baseScene.elements.begin(), baseScene.elements.end(), [](const auto& element) {
78 return !validElement(element);
79 }))
81 Diagnostic::error(DiagnosticCode::InvalidArgument, "vegetation live-element base scene is invalid", {}, {},
82 "asset.graphics.vegetation-live-elements"));
83 try {
85 std::unique_ptr<VegetationSceneLiveElements>(new VegetationSceneLiveElements(std::move(baseScene), owner)));
86 } catch (const std::bad_alloc&) {
88 Diagnostic::error(DiagnosticCode::Failed, "vegetation live-element registry allocation failed", {}, {},
89 "asset.graphics.vegetation-live-elements"));
90 }
91}
92
94 try {
95 LoadedVegetationScene result = baseScene_;
96 result.elements.reserve(baseScene_.elements.size() + slots_.size());
97 for (const auto& slot : slots_)
98 if (slot.element) result.elements.push_back(*slot.element);
99 return Result<LoadedVegetationScene>::success(std::move(result));
100 } catch (const std::bad_alloc&) {
102 Diagnostic::error(DiagnosticCode::Failed, "vegetation live-element snapshot allocation failed", {}, {},
103 "asset.graphics.vegetation-live-elements"));
104 }
105}
106
108 std::uint64_t expectedRevision, std::uint64_t expectedGpuRevision, const VegetationSceneElement& element,
109 VegetationSceneGpuRuntime& runtime, const graphics::PbrSurface& baseSurface,
110 const graphics::VegetationMotion& baseMotion, const std::map<std::string, graphics::VegetationMask>& masks,
111 const VegetationSceneGpuBuild& build) {
112 if (expectedRevision != revision_ || expectedGpuRevision != runtime.sourceRevision())
114 Diagnostic::error(DiagnosticCode::Conflict, "vegetation live-element state changed before registration", {},
115 {}, "asset.graphics.vegetation-live-elements"));
116 if (revision_ == std::numeric_limits<std::uint64_t>::max() || !validElement(element))
118 Diagnostic::error(DiagnosticCode::InvalidArgument, "vegetation live Element is invalid", {}, {},
119 "asset.graphics.vegetation-live-elements"));
120 std::size_t slotIndex = 0;
121 while (slotIndex < slots_.size() && (slots_[slotIndex].element || slots_[slotIndex].retired)) ++slotIndex;
122 const auto activeCount = std::count_if(slots_.begin(), slots_.end(), [](const Slot& slot) {
123 return slot.element.has_value();
124 });
125 if (baseScene_.elements.size() + std::size_t(activeCount) + 1 > 4096)
127 Diagnostic::error(DiagnosticCode::InvalidArgument, "vegetation live-element capacity exceeded", {}, {},
128 "asset.graphics.vegetation-live-elements"));
129 auto candidate = snapshot();
130 if (!candidate) return Result<VegetationSceneElementPublication>::failure(candidate.status());
131 try {
132 candidate.value().elements.push_back(element);
133 if (slotIndex == slots_.size()) slots_.reserve(slots_.size() + 1);
134 } catch (const std::bad_alloc&) {
136 Diagnostic::error(DiagnosticCode::Failed, "vegetation live-element registration allocation failed", {}, {},
137 "asset.graphics.vegetation-live-elements"));
138 }
139 auto published = runtime.replace(expectedGpuRevision, baseSurface, baseMotion, candidate.value(), masks, build);
140 if (!published) return Result<VegetationSceneElementPublication>::failure(published.status());
141 if (slotIndex == slots_.size()) slots_.push_back({});
142 auto& slot = slots_[slotIndex];
143 slot.element.emplace(std::move(candidate.value().elements.back()));
144 ++revision_;
146 {{owner_, static_cast<VegetationSceneElementHandle::index_type>(slotIndex), slot.generation}, revision_,
147 published.value()});
148}
149
151 std::uint64_t expectedRevision, std::uint64_t expectedGpuRevision, VegetationSceneElementHandle handle,
152 VegetationSceneGpuRuntime& runtime, const graphics::PbrSurface& baseSurface,
153 const graphics::VegetationMotion& baseMotion, const std::map<std::string, graphics::VegetationMask>& masks,
154 const VegetationSceneGpuBuild& build) {
155 if (expectedRevision != revision_ || expectedGpuRevision != runtime.sourceRevision())
157 Diagnostic::error(DiagnosticCode::Conflict, "vegetation live-element state changed before withdrawal", {},
158 {}, "asset.graphics.vegetation-live-elements"));
159 if (!handle.isValid() || handle.owner() != owner_ || handle.index() >= slots_.size())
161 Diagnostic::error(DiagnosticCode::NotFound, "vegetation live Element handle is foreign or missing", {}, {},
162 "asset.graphics.vegetation-live-elements"));
163 auto& slot = slots_[handle.index()];
164 if (!slot.element || slot.generation != handle.generation())
166 Diagnostic::error(DiagnosticCode::NotFound, "vegetation live Element handle is stale or withdrawn", {}, {},
167 "asset.graphics.vegetation-live-elements"));
168 if (revision_ == std::numeric_limits<std::uint64_t>::max())
170 Diagnostic::error(DiagnosticCode::InvalidArgument, "vegetation live-element revision is exhausted", {}, {},
171 "asset.graphics.vegetation-live-elements"));
172 auto candidate = snapshot();
173 if (!candidate) return Result<VegetationSceneElementPublication>::failure(candidate.status());
174 const std::size_t dynamicOffset = baseScene_.elements.size();
175 std::size_t activeBefore = 0;
176 for (std::size_t index = 0; index < handle.index(); ++index)
177 if (slots_[index].element) ++activeBefore;
178 candidate.value().elements.erase(candidate.value().elements.begin() + dynamicOffset + activeBefore);
179 auto published = runtime.replace(expectedGpuRevision, baseSurface, baseMotion, candidate.value(), masks, build);
180 if (!published) return Result<VegetationSceneElementPublication>::failure(published.status());
181 slot.element.reset();
182 const auto next = VegetationSceneElementHandle::LocalHandle::nextGeneration(slot.generation);
183 if (next)
184 slot.generation = *next;
185 else
186 slot.retired = true;
187 ++revision_;
188 return Result<VegetationSceneElementPublication>::success({handle, revision_, published.value()});
189}
190
191} // namespace eve::asset_graphics
double value
std::map< std::string, Var > values
float u
Definition Grass.cpp:233
std::map< std::string, PropertyRule > properties
bool finite
PrimitiveHandle handle
std::string element
uint32_t index
Transactional runtime registration of TVE Element volumes.
static Result< AssetRef > parse(std::string_view text)
Parse an asset://<canonical UUID> reference.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
constexpr std::optional< RuntimeHandle > nextGeneration() const noexcept
Returns this slot at its next generation.
Instance-qualified handle for one dynamically registered TVE Element volume.
Owning GPU publication of one immutable TVE manager scene. The resource factory, mask map and scene a...
Owning registry that atomically couples dynamic Element state to a scene GPU runtime....
Result< LoadedVegetationScene > snapshot() const
Detached scene containing imported Elements followed by live slots in stable index order.
static Result< std::unique_ptr< VegetationSceneLiveElements > > create(LoadedVegetationScene baseScene, std::uint64_t owner)
Create a registry from one validated imported scene.
Result< VegetationSceneElementPublication > registerElement(std::uint64_t expectedRevision, std::uint64_t expectedGpuRevision, const VegetationSceneElement &element, VegetationSceneGpuRuntime &runtime, const graphics::PbrSurface &baseSurface, const graphics::VegetationMotion &baseMotion, const std::map< std::string, graphics::VegetationMask > &masks, const VegetationSceneGpuBuild &build)
Register and publish one Element as an atomic registry/GPU transaction.
Result< VegetationSceneElementPublication > withdrawElement(std::uint64_t expectedRevision, std::uint64_t expectedGpuRevision, VegetationSceneElementHandle handle, VegetationSceneGpuRuntime &runtime, const graphics::PbrSurface &baseSurface, const graphics::VegetationMotion &baseMotion, const std::map< std::string, graphics::VegetationMask > &masks, const VegetationSceneGpuBuild &build)
Withdraw and publish one live Element as an atomic registry/GPU transaction. Foreign,...
bool validGuid(std::string_view value)
Valid guid.
Fully validated, detached scene-manager candidate with no archive or GPU borrows.
std::vector< VegetationSceneElement > elements
One normalized Unity TVEElement definition awaiting texture realization.
Explicit detached inputs for publishing all nine TVE scene-manager field layers.
Owning material parameter snapshot; texture pointers remain borrowed. Base color/metallic/roughness c...
Definition PbrSurface.h:218
Source-equivalent plant motion parameters with explicit time and texture inputs. All data is owned....