载入中...
搜索中...
未找到
VegetationDetails.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <initializer_list>
6#include <stdexcept>
7
8namespace eve::graphics {
9namespace {
10void exactFields(const Value& value, std::initializer_list<std::string_view> names) {
11 const auto* object = value.getIf<Value::Object>();
12 if (!object || object->size() != names.size()) throw std::invalid_argument("unexpected Global Details fields");
13 for (const auto name : names)
14 if (!object->contains(std::string(name))) throw std::invalid_argument("missing Global Details field");
15}
16
17const Value& member(const Value& value, std::string_view name) {
18 return value.getIf<Value::Object>()->at(std::string(name));
19}
20
21float finiteNumber(const Value& value) {
22 if (!value.isInt64() && !value.isDouble()) throw std::invalid_argument("Global Details number is invalid");
23 const float result = value.isDouble() ? float(value.asDouble()) : float(value.asInt());
24 if (!std::isfinite(result)) throw std::invalid_argument("Global Details number is non-finite");
25 return result;
26}
27
28uint8_t layerNumber(const Value& value) {
29 if (!value.isInt64() || value.asInt() < 0 || value.asInt() > 8)
30 throw std::invalid_argument("Global Details layer is outside [0,8]");
31 return uint8_t(value.asInt());
32}
33} // namespace
34
36 const VegetationMotion& baseMotion,
38 auto unit = [](float value) { return std::isfinite(value) && value >= 0 && value <= 1; };
39 auto range = [](float value, float maximum) { return std::isfinite(value) && value >= 0 && value <= maximum; };
40 if (s.colorsLayer > 8 || s.extrasLayer > 8 || s.motionLayer > 8 || !unit(s.globalColor) || !unit(s.globalAlpha) ||
41 !unit(s.globalOverlay) || !unit(s.globalWetness) || !unit(s.colorMaskMinimum) || !unit(s.colorMaskMaximum) ||
42 !unit(s.overlayMaskMinimum) || !unit(s.overlayMaskMaximum) || !unit(s.alphaThreshold) ||
43 s.colorMaskMaximum - s.colorMaskMinimum + .0001f == 0 ||
44 s.overlayMaskMaximum - s.overlayMaskMinimum + .0001f == 0 || !range(s.perspectivePush, 4) ||
45 !range(s.perspectiveNoise, 4) || !range(s.perspectiveAngle, 8) || !range(s.bendingAmplitude, 2) ||
46 !range(s.bendingSpeed, 40) || !range(s.bendingScale, 20) || !range(s.flutterAmplitude, 2) ||
47 !range(s.flutterSpeed, 40) || !range(s.flutterScale, 20) || !range(s.interactionAmplitude, 2))
49 DiagnosticCode::InvalidArgument, "invalid TVE Global Details values", {}, {}, "graphics.vegetation"));
50 for (float value : s.motionHighlight)
51 if (!std::isfinite(value) || value < 0)
53 DiagnosticCode::InvalidArgument, "invalid TVE motion highlight", {}, {}, "graphics.vegetation"));
54
55 VegetationDetailRuntime result{baseSurface, baseMotion, s.colorMaskMinimum,
56 s.colorMaskMaximum, s.overlayMaskMinimum, s.overlayMaskMaximum,
57 s.alphaThreshold - .5f};
58 result.surface.vegetationColors.layer = s.colorsLayer;
59 result.surface.vegetationExtras.layer = s.extrasLayer;
60 result.surface.vegetationMotion.layer = s.motionLayer;
61 result.surface.vegetationColor.colorsCoverage *= s.globalColor;
62 result.surface.vegetationColor.overlay *= s.globalOverlay;
63 result.surface.vegetationColor.wetness *= s.globalWetness;
64 result.surface.vegetationColor.globalColorMaskMinimum = s.colorMaskMinimum;
65 result.surface.vegetationColor.globalColorMaskMaximum = s.colorMaskMaximum;
66 result.surface.vegetationColor.globalOverlayMaskMinimum = s.overlayMaskMinimum;
67 result.surface.vegetationColor.globalOverlayMaskMaximum = s.overlayMaskMaximum;
68 result.surface.vegetationColor.globalAlphaThresholdOffset = s.alphaThreshold - .5f;
69 const float materialAlpha = result.surface.vegetationAlpha.enabled ? result.surface.vegetationAlpha.global : 1.f;
70 result.surface.vegetationAlpha.enabled = true;
71 result.surface.vegetationAlpha.global = materialAlpha * s.globalAlpha;
72 result.surface.motionHighlightColor = s.motionHighlight;
73 auto& gpu = result.surface.vegetationMotion;
74 gpu.bending = s.bendingAmplitude;
75 gpu.bendingSpeed = s.bendingSpeed;
76 gpu.bendingScale = s.bendingScale;
77 gpu.flutter = s.flutterAmplitude;
78 gpu.flutterSpeed = s.flutterSpeed;
79 gpu.flutterScale = s.flutterScale;
80 gpu.interaction = s.interactionAmplitude;
81 gpu.perspectivePush = s.perspectivePush;
82 gpu.perspectiveNoise = s.perspectiveNoise;
83 gpu.perspectiveAngle = s.perspectiveAngle;
84 auto& cpu = result.motion;
85 cpu.motionLayer = s.motionLayer;
86 cpu.bending = gpu.bending;
87 cpu.bendingSpeed = gpu.bendingSpeed;
88 cpu.bendingScale = gpu.bendingScale;
89 cpu.flutter = gpu.flutter;
90 cpu.flutterSpeed = gpu.flutterSpeed;
91 cpu.flutterScale = gpu.flutterScale;
92 cpu.interaction = gpu.interaction;
93 cpu.perspectivePush = gpu.perspectivePush;
94 cpu.perspectiveNoise = gpu.perspectiveNoise;
95 cpu.perspectiveAngle = gpu.perspectiveAngle;
96 auto valid = validatePbrSurface(result.surface);
98 return Result<VegetationDetailRuntime>::success(std::move(result));
99}
100
103 if (!validated) return Result<Value>::failure(validated.status());
104 try {
106 {{"schema", "eve.graphics.vegetation-details"},
107 {"version", 1},
108 {"layers",
109 Value::array({int(settings.colorsLayer), int(settings.extrasLayer), int(settings.motionLayer)})},
110 {"global", Value::array({settings.globalColor, settings.globalAlpha, settings.globalOverlay,
111 settings.globalWetness})},
112 {"colorMask", Value::array({settings.colorMaskMinimum, settings.colorMaskMaximum})},
113 {"overlayMask", Value::array({settings.overlayMaskMinimum, settings.overlayMaskMaximum})},
114 {"alphaThreshold", settings.alphaThreshold},
115 {"perspective",
116 Value::array({settings.perspectivePush, settings.perspectiveNoise, settings.perspectiveAngle})},
117 {"motionHighlight",
118 Value::array({settings.motionHighlight[0], settings.motionHighlight[1], settings.motionHighlight[2]})},
119 {"bending", Value::array({settings.bendingAmplitude, settings.bendingSpeed, settings.bendingScale})},
120 {"flutter", Value::array({settings.flutterAmplitude, settings.flutterSpeed, settings.flutterScale})},
121 {"interactionAmplitude", settings.interactionAmplitude}}));
122 } catch (const std::bad_alloc&) {
124 Diagnostic::error(DiagnosticCode::Failed, "Global Details snapshot allocation failed"));
125 }
126}
127
129 try {
130 exactFields(document, {"schema", "version", "layers", "global", "colorMask", "overlayMask", "alphaThreshold",
131 "perspective", "motionHighlight", "bending", "flutter", "interactionAmplitude"});
132 if (!member(document, "schema").isString() ||
133 member(document, "schema").asString() != "eve.graphics.vegetation-details")
134 throw std::invalid_argument("unexpected Global Details schema");
135 if (!member(document, "version").isInt64() || member(document, "version").asInt() != 1)
137 Diagnostic::error(DiagnosticCode::UnknownVersion, "only Global Details version 1 is supported"));
138 auto numbers = [&](std::string_view name, size_t count) {
139 const auto* array = member(document, name).getIf<Value::Array>();
140 if (!array || array->size() != count)
141 throw std::invalid_argument("Global Details vector length is invalid");
142 std::array<float, 4> result{};
143 for (size_t index = 0; index < count; ++index) result[index] = finiteNumber((*array)[index]);
144 return result;
145 };
146 const auto* layers = member(document, "layers").getIf<Value::Array>();
147 if (!layers || layers->size() != 3) throw std::invalid_argument("Global Details layers are invalid");
149 result.colorsLayer = layerNumber((*layers)[0]);
150 result.extrasLayer = layerNumber((*layers)[1]);
151 result.motionLayer = layerNumber((*layers)[2]);
152 const auto global = numbers("global", 4);
153 result.globalColor = global[0];
154 result.globalAlpha = global[1];
155 result.globalOverlay = global[2];
156 result.globalWetness = global[3];
157 const auto colorMask = numbers("colorMask", 2);
158 result.colorMaskMinimum = colorMask[0];
159 result.colorMaskMaximum = colorMask[1];
160 const auto overlayMask = numbers("overlayMask", 2);
161 result.overlayMaskMinimum = overlayMask[0];
162 result.overlayMaskMaximum = overlayMask[1];
163 result.alphaThreshold = finiteNumber(member(document, "alphaThreshold"));
164 const auto perspective = numbers("perspective", 3);
165 result.perspectivePush = perspective[0];
166 result.perspectiveNoise = perspective[1];
167 result.perspectiveAngle = perspective[2];
168 const auto highlight = numbers("motionHighlight", 3);
169 std::copy_n(highlight.begin(), 3, result.motionHighlight.begin());
170 const auto bending = numbers("bending", 3);
171 result.bendingAmplitude = bending[0];
172 result.bendingSpeed = bending[1];
173 result.bendingScale = bending[2];
174 const auto flutter = numbers("flutter", 3);
175 result.flutterAmplitude = flutter[0];
176 result.flutterSpeed = flutter[1];
177 result.flutterScale = flutter[2];
178 result.interactionAmplitude = finiteNumber(member(document, "interactionAmplitude"));
179 auto validated = configureVegetationDetails(PbrSurface{}, VegetationMotion{}, result);
180 if (!validated) return Result<VegetationDetailSettings>::failure(validated.status());
181 return Result<VegetationDetailSettings>::success(std::move(result));
182 } catch (const std::invalid_argument& error) {
184 Diagnostic::error(DiagnosticCode::InvalidArgument, error.what(), {}, {}, "graphics.vegetation.details"));
185 } catch (const std::bad_alloc&) {
187 Diagnostic::error(DiagnosticCode::Failed, "Global Details restore allocation failed"));
188 }
189}
190
191} // namespace eve::graphics
double value
const std::string & s
float maximum[3]
Range range
std::string name
bool valid
std::string error
Definition Package.cpp:60
std::string string
std::uint32_t count
TacticalUnit * unit
TerrainThermalSettings settings
Heightmap global
Json object
float(ui::Theme::* member)[4]
uint32_t index
std::size_t at
float highlight
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
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
static Value array(Array value)
Compatibility factory for an array value.
Definition Value.h:112
std::vector< Value > Array
Definition Value.h:33
static Value object(Object value)
Compatibility factory for an object value.
Definition Value.h:114
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
Result< VegetationDetailSettings > restoreVegetationDetails(const Value &document)
Decode one exact Global Details document transactionally.
Result< Value > snapshotVegetationDetails(const VegetationDetailSettings &settings)
Encode one owning Global Details document using eve.graphics.vegetation-details/1.
Result< void > validatePbrSurface(const PbrSurface &s)
Validate finite material factors and sampler enums without changing the input.
Definition PbrSurface.cpp:4
Result< VegetationDetailRuntime > configureVegetationDetails(const PbrSurface &baseSurface, const VegetationMotion &baseMotion, const VegetationDetailSettings &s)
Validate and project TVE Global Details into native PBR and motion snapshots.
Owning material parameter snapshot; texture pointers remain borrowed. Base color/metallic/roughness c...
Definition PbrSurface.h:218
Detached render values produced from one validated Global Details publication. PBR texture pointers r...
TVE Global Details values, independent of scene components and global shader state.
Source-equivalent plant motion parameters with explicit time and texture inputs. All data is owned....