载入中...
搜索中...
未找到
VegetationFieldCodec.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <cmath>
3#include <initializer_list>
4#include <new>
5#include <stdexcept>
7
8namespace eve::graphics {
9namespace {
10using Object = Value::Object;
11void fields(const Value& v, std::initializer_list<std::string_view> names) {
12 if (!v.isObject() || v.getIf<Value::Object>()->size() != names.size())
13 throw std::invalid_argument("unexpected field set");
14 for (auto name : names)
15 if (!v.find(std::string(name))) throw std::invalid_argument("missing field " + std::string(name));
16}
17const Value& at(const Value& v, std::string_view name) { return v.getIf<Value::Object>()->at(std::string(name)); }
18float number(const Value& v) {
19 if (!v.isInt64() && !v.isDouble()) throw std::invalid_argument("expected finite number");
20 const double d = v.isDouble() ? v.asDouble() : double(v.asInt());
21 const float f = float(d);
22 if (!std::isfinite(f)) throw std::invalid_argument("expected finite float");
23 return f;
24}
25int integer(const Value& v, int low, int high) {
26 if (!v.isInt64() || v.asInt() < low || v.asInt() > high) throw std::invalid_argument("integer out of range");
27 return int(v.asInt());
28}
29glm::vec4 vector(const Value& v, size_t count) {
30 if (!v.isArray() || v.getIf<Value::Array>()->size() != count) throw std::invalid_argument("invalid vector length");
31 glm::vec4 result(0.f);
32 for (size_t i = 0; i < count; ++i) result[int(i)] = number((*v.getIf<Value::Array>())[i]);
33 return result;
34}
35Value encode(glm::vec4 v) { return Value::array({v.x, v.y, v.z, v.w}); }
36Value encode(glm::vec3 v) { return Value::array({v.x, v.y, v.z}); }
37} // namespace
38
40 try {
41 fields(document, {"schema", "version", "globals", "elements"});
42 const auto& schema = at(document, "schema");
43 if (!schema.isString() || schema.asString() != "eve.graphics.vegetation-field")
44 throw std::invalid_argument("unexpected vegetation schema");
45 const auto& version = at(document, "version");
46 if (!version.isInt64() || version.asInt() != 1)
48 Diagnostic::error(DiagnosticCode::UnknownVersion, "only vegetation field version 1 is supported"));
49 const auto& g = at(document, "globals");
50 fields(g, {"color", "extras", "motion", "vertex", "season"});
51 VegetationGlobals globals;
52 globals.color = vector(at(g, "color"), 4);
53 globals.extras = vector(at(g, "extras"), 4);
54 globals.motion = vector(at(g, "motion"), 4);
55 globals.vertex = vector(at(g, "vertex"), 4);
56 globals.season = number(at(g, "season"));
57 const auto& source = at(document, "elements");
58 if (!source.isArray() || source.getIf<Value::Array>()->size() > 4096)
59 throw std::invalid_argument("invalid element count");
60 std::vector<VegetationElement> elements;
61 size_t totalPixels = 0;
62 for (const auto& entry : (*source.getIf<Value::Array>())) {
63 fields(entry, {"channel", "blend", "shape", "center", "extents", "yaw", "opacity", "edgeFade", "layers",
64 "priority", "value", "seasonal", "seasons", "mask"});
66 e.channel = VegetationChannel(integer(at(entry, "channel"), 0, 3));
67 e.blend = VegetationBlend(integer(at(entry, "blend"), 0, 4));
68 e.shape = VegetationShape(integer(at(entry, "shape"), 0, 1));
69 e.center = glm::vec3(vector(at(entry, "center"), 3));
70 e.extents = glm::vec3(vector(at(entry, "extents"), 3));
71 e.yaw = number(at(entry, "yaw"));
72 e.opacity = number(at(entry, "opacity"));
73 e.edgeFade = number(at(entry, "edgeFade"));
74 e.layers = uint16_t(integer(at(entry, "layers"), 1, 511));
75 e.priority = integer(at(entry, "priority"), INT32_MIN, INT32_MAX);
76 e.value = vector(at(entry, "value"), 4);
77 if (!at(entry, "seasonal").isBool()) throw std::invalid_argument("seasonal must be boolean");
78 e.seasonal = at(entry, "seasonal").asBool();
79 const auto& seasons = at(entry, "seasons");
80 if (!seasons.isArray() || seasons.getIf<Value::Array>()->size() != 4)
81 throw std::invalid_argument("four seasons required");
82 for (size_t i = 0; i < 4; ++i) e.seasons[i] = vector((*seasons.getIf<Value::Array>())[i], 4);
83 const auto& mask = at(entry, "mask");
84 fields(mask, {"width", "height", "pixels"});
85 e.mask.width = uint32_t(integer(at(mask, "width"), 0, 2048));
86 e.mask.height = uint32_t(integer(at(mask, "height"), 0, 2048));
87 const auto& pixels = at(mask, "pixels");
88 if (!pixels.isArray() || pixels.getIf<Value::Array>()->size() != size_t(e.mask.width) * e.mask.height)
89 throw std::invalid_argument("mask pixel count mismatch");
90 totalPixels += pixels.getIf<Value::Array>()->size();
91 if (totalPixels > 4 * 1024 * 1024) throw std::invalid_argument("mask pixel budget exceeded");
92 for (const auto& pixel : (*pixels.getIf<Value::Array>())) e.mask.pixels.push_back(vector(pixel, 4));
93 elements.push_back(std::move(e));
94 }
95 return replace(globals, elements);
96 } catch (const std::invalid_argument& error) {
98 Diagnostic::error(DiagnosticCode::InvalidArgument, error.what(), {}, {}, "graphics.vegetation"));
99 } catch (const std::bad_alloc&) {
100 return Result<void>::failure(Diagnostic::error(DiagnosticCode::Failed, "vegetation restore allocation failed"));
101 }
102}
103
105 try {
107 for (const auto& e : elements_) {
108 Value::Array seasons, pixels;
109 for (auto season : e.seasons) seasons.push_back(encode(season));
110 for (auto pixel : e.mask.pixels) pixels.push_back(encode(pixel));
111 elements.push_back(Value::object({{"channel", int(e.channel)},
112 {"blend", int(e.blend)},
113 {"shape", int(e.shape)},
114 {"center", encode(e.center)},
115 {"extents", encode(e.extents)},
116 {"yaw", e.yaw},
117 {"opacity", e.opacity},
118 {"edgeFade", e.edgeFade},
119 {"layers", int(e.layers)},
120 {"priority", e.priority},
121 {"value", encode(e.value)},
122 {"seasonal", e.seasonal},
123 {"seasons", Value(std::move(seasons))},
124 {"mask", Value::object({{"width", int(e.mask.width)},
125 {"height", int(e.mask.height)},
126 {"pixels", Value(std::move(pixels))}})}}));
127 }
128 return Result<Value>::success(Value::object({{"schema", "eve.graphics.vegetation-field"},
129 {"version", 1},
130 {"globals", Value::object({{"color", encode(globals_.color)},
131 {"extras", encode(globals_.extras)},
132 {"motion", encode(globals_.motion)},
133 {"vertex", encode(globals_.vertex)},
134 {"season", globals_.season}})},
135 {"elements", Value(std::move(elements))}}));
136 } catch (const std::bad_alloc&) {
138 Diagnostic::error(DiagnosticCode::Failed, "vegetation snapshot allocation failed"));
139 }
140}
141} // namespace eve::graphics
int mask
tensor::Graph g
Definition GpuGraph.cpp:7
float v
std::string name
std::string error
Definition Package.cpp:60
float f
std::vector< std::string > fields
Definition PlayHost.cpp:111
float d
uint8_t * pixels
double number
std::string string
std::uint32_t count
std::size_t elements
float size
Definition TreeMesh.cpp:156
const UnitySourceAsset & source
std::size_t at
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
Result< void > replace(const VegetationGlobals &globals, std::span< const VegetationElement > elements)
Validate and atomically replace the entire field; failure preserves prior state.
Result< void > restore(const Value &document)
Decode eve.graphics.vegetation-field version 1; rejects unknown fields/versions. Single-writer,...
Result< Value > snapshot() const
Owning versioned snapshot; thread-safe while no mutation occurs. No callbacks.
char * encode(std::string format, const char *src, size_t srclen, size_t &dstlen, size_t linelen)
Encodes raw bytes (e.g. hex / base64) into a text buffer.
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
VegetationBlend
Ordered field composition operation.
VegetationChannel
Independent vegetation field channels; values use linear color and world units.
VegetationShape
Analytic influence shape in an element's local coordinates.
int64_t integer(const RuntimeTensor &v, size_t i=0)
Integer.
Owning element definition; no scene, texture or entity pointers survive admission....
Owning global defaults. Extras = emission, wetness, overlay, alpha. Motion = signed world X/Z directi...