载入中...
搜索中...
未找到
WaterStyleConfig.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
4
5#include <cmath>
6#include <initializer_list>
7#include <set>
8
9namespace eve::graphics {
10namespace {
11
12const Value::Object* objectAt(const Value& value, const char* name) {
13 const Value* field = value.find(name);
14 return field ? field->getIf<Value::Object>() : nullptr;
15}
16
17bool exactFields(const Value::Object& object, std::initializer_list<const char*> fields) {
18 if (object.size() != fields.size()) return false;
19 for (const char* field : fields)
20 if (!object.contains(field)) return false;
21 return true;
22}
23
24bool numberAt(const Value::Object& object, const char* name, float& output) {
25 const auto found = object.find(name);
26 if (found == object.end() || (!found->second.isDouble() && !found->second.isInt64())) return false;
27 output = static_cast<float>(found->second.isDouble() ? found->second.asDouble() : found->second.asInt());
28 return std::isfinite(output);
29}
30
31bool integerAt(const Value::Object& object, const char* name, int& output) {
32 const auto found = object.find(name);
33 if (found == object.end() || !found->second.isInt64()) return false;
34 output = static_cast<int>(found->second.asInt());
35 return true;
36}
37
38bool boolAt(const Value::Object& object, const char* name, bool& output) {
39 const auto found = object.find(name);
40 if (found == object.end() || !found->second.isBool()) return false;
41 output = found->second.asBool();
42 return true;
43}
44
45bool vec3At(const Value::Object& object, const char* name, glm::vec3& output) {
46 const auto found = object.find(name);
47 if (found == object.end()) return false;
48 const auto* values = found->second.getIf<Value::Array>();
49 if (!values || values->size() != 3) return false;
50 for (int i = 0; i < 3; ++i) {
51 if (!(*values)[i].isDouble() && !(*values)[i].isInt64()) return false;
52 output[i] = static_cast<float>((*values)[i].isDouble() ? (*values)[i].asDouble() : (*values)[i].asInt());
53 if (!std::isfinite(output[i])) return false;
54 }
55 return true;
56}
57
58Value vec3Value(const glm::vec3& value) {
59 return Value::array({value.x, value.y, value.z});
60}
61
62bool color(const glm::vec3& value) {
63 return std::isfinite(value.x) && std::isfinite(value.y) && std::isfinite(value.z) &&
64 glm::all(glm::greaterThanEqual(value, glm::vec3(0.0F))) &&
65 glm::all(glm::lessThanEqual(value, glm::vec3(8.0F)));
66}
67
68} // namespace
69
73 Diagnostic::error(DiagnosticCode::InvalidArgument, "water colors must be finite and in [0, 8]", "$.colors", {}, "graphics.water"));
74 if (!std::isfinite(waveSpeed) || waveSpeed < -20.0F || waveSpeed > 20.0F ||
75 !std::isfinite(waveAmplitude) || waveAmplitude < 0.0F || waveAmplitude > 4.0F ||
76 !std::isfinite(waveScale) || waveScale < 0.01F || waveScale > 256.0F ||
77 !std::isfinite(waveSharpness) || waveSharpness < 0.1F || waveSharpness > 8.0F ||
78 !std::isfinite(rippleAmplitude) || rippleAmplitude < 0.0F || rippleAmplitude > 4.0F ||
79 rippleCount < 0 || rippleCount > 8 || !std::isfinite(rippleInterval) || rippleInterval < 0.05F ||
80 rippleInterval > 60.0F)
82 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid wave or ripple parameter", "$.waves", {}, "graphics.water"));
83 if (!std::isfinite(depthDistance) || depthDistance <= 0.0F || depthDistance > 10000.0F ||
84 !std::isfinite(opacity) || opacity < 0.0F || opacity > 1.0F)
86 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid depth parameter", "$.depth", {}, "graphics.water"));
87 if (!std::isfinite(foamWidth) || foamWidth <= 0.0F || foamWidth > 1000.0F ||
88 !std::isfinite(foamSoftness) || foamSoftness < 0.0F || foamSoftness > 1.0F ||
89 !std::isfinite(foamStrength) || foamStrength < 0.0F || foamStrength > 4.0F)
91 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid foam parameter", "$.foam", {}, "graphics.water"));
92 if (!std::isfinite(fresnelPower) || fresnelPower < 0.01F || fresnelPower > 32.0F ||
93 !std::isfinite(reflectionIntensity) || reflectionIntensity < 0.0F || reflectionIntensity > 4.0F ||
94 !std::isfinite(sunIntensity) || sunIntensity < 0.0F || sunIntensity > 8.0F ||
98 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid lighting parameter", "$.lighting", {}, "graphics.water"));
99 if (!std::isfinite(refractionStrength) || refractionStrength < 0.0F || refractionStrength > 0.25F)
101 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid refraction strength", "$.refraction.strength", {}, "graphics.water"));
102 if (!std::isfinite(causticsStrength) || causticsStrength < 0.0F || causticsStrength > 4.0F ||
103 !std::isfinite(causticsScale) || causticsScale < 0.01F || causticsScale > 256.0F)
105 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid caustics parameter", "$.caustics", {}, "graphics.water"));
106 return Result<void>::success();
107}
108
110 auto valid = validate();
111 if (!valid) return Result<Value>::failure(valid.status());
112 Value::Object colors{{"deep", vec3Value(deepColor)}, {"shallow", vec3Value(shallowColor)},
113 {"foam", vec3Value(foamColor)}, {"reflectionTint", vec3Value(reflectionTint)}};
114 Value::Object waves{{"speed", waveSpeed}, {"amplitude", waveAmplitude}, {"scale", waveScale},
115 {"sharpness", waveSharpness}, {"rippleAmplitude", rippleAmplitude},
116 {"rippleCount", static_cast<std::int64_t>(rippleCount)}, {"rippleInterval", rippleInterval}};
117 Value::Object depth{{"distance", depthDistance}, {"opacity", opacity}};
118 Value::Object foam{{"width", foamWidth}, {"softness", foamSoftness}, {"strength", foamStrength}};
119 Value::Object lighting{{"fresnelPower", fresnelPower}, {"reflectionIntensity", reflectionIntensity},
120 {"sunIntensity", sunIntensity}, {"screenSpaceReflection", screenSpaceReflection},
121 {"screenSpaceReflectionStrength", screenSpaceReflectionStrength}};
122 Value::Object refraction{{"strength", refractionStrength}};
123 Value::Object caustics{{"strength", causticsStrength}, {"scale", causticsScale}};
125 {"schema", std::string(SchemaId)}, {"schemaVersion", static_cast<std::int64_t>(SchemaVersion)},
126 {"unknownFields", "reject"}, {"colors", Value(std::move(colors))}, {"waves", Value(std::move(waves))},
127 {"depth", Value(std::move(depth))}, {"foam", Value(std::move(foam))},
128 {"lighting", Value(std::move(lighting))}, {"refraction", Value(std::move(refraction))},
129 {"caustics", Value(std::move(caustics))},
130 }));
131}
132
134 const auto* root = value.getIf<Value::Object>();
135 if (!root || !exactFields(*root, {"schema", "schemaVersion", "unknownFields", "colors", "waves", "depth",
136 "foam", "lighting", "refraction", "caustics"}))
138 "water definition requires exactly ten known fields",
139 "$", {}, "graphics.water"));
140 if (!root->at("schema").isString() || root->at("schema").asString() != SchemaId ||
141 !root->at("schemaVersion").isInt64() || root->at("schemaVersion").asInt() != SchemaVersion)
143 "unsupported water schema/version",
144 "$.schemaVersion", {}, "graphics.water"));
145 if (!root->at("unknownFields").isString() || root->at("unknownFields").asString() != "reject")
147 Diagnostic::error({}, "water v1 requires unknownFields=reject", "$.unknownFields", {}, "graphics.water"));
148
149 const auto* colors = objectAt(value, "colors");
150 const auto* waves = objectAt(value, "waves");
151 const auto* depth = objectAt(value, "depth");
152 const auto* foam = objectAt(value, "foam");
153 const auto* lighting = objectAt(value, "lighting");
154 const auto* refraction = objectAt(value, "refraction");
155 const auto* caustics = objectAt(value, "caustics");
156 if (!colors || !waves || !depth || !foam || !lighting || !refraction || !caustics ||
157 !exactFields(*colors, {"deep", "shallow", "foam", "reflectionTint"}) ||
158 !exactFields(*waves, {"speed", "amplitude", "scale", "sharpness", "rippleAmplitude", "rippleCount", "rippleInterval"}) ||
159 !exactFields(*depth, {"distance", "opacity"}) ||
160 !exactFields(*foam, {"width", "softness", "strength"}) ||
161 !exactFields(*lighting, {"fresnelPower", "reflectionIntensity", "sunIntensity", "screenSpaceReflection", "screenSpaceReflectionStrength"}) ||
162 !exactFields(*refraction, {"strength"}) || !exactFields(*caustics, {"strength", "scale"}))
164 DiagnosticCode::InvalidArgument, "invalid or unknown nested water field", "$", {}, "graphics.water"));
165
167 if (!vec3At(*colors, "deep", output.deepColor) || !vec3At(*colors, "shallow", output.shallowColor) ||
168 !vec3At(*colors, "foam", output.foamColor) || !vec3At(*colors, "reflectionTint", output.reflectionTint) ||
169 !numberAt(*waves, "speed", output.waveSpeed) || !numberAt(*waves, "amplitude", output.waveAmplitude) ||
170 !numberAt(*waves, "scale", output.waveScale) || !numberAt(*waves, "sharpness", output.waveSharpness) ||
171 !numberAt(*waves, "rippleAmplitude", output.rippleAmplitude) || !integerAt(*waves, "rippleCount", output.rippleCount) ||
172 !numberAt(*waves, "rippleInterval", output.rippleInterval) || !numberAt(*depth, "distance", output.depthDistance) ||
173 !numberAt(*depth, "opacity", output.opacity) || !numberAt(*foam, "width", output.foamWidth) ||
174 !numberAt(*foam, "softness", output.foamSoftness) || !numberAt(*foam, "strength", output.foamStrength) ||
175 !numberAt(*lighting, "fresnelPower", output.fresnelPower) ||
176 !numberAt(*lighting, "reflectionIntensity", output.reflectionIntensity) ||
177 !numberAt(*lighting, "sunIntensity", output.sunIntensity) ||
178 !boolAt(*lighting, "screenSpaceReflection", output.screenSpaceReflection) ||
179 !numberAt(*lighting, "screenSpaceReflectionStrength", output.screenSpaceReflectionStrength) ||
180 !numberAt(*refraction, "strength", output.refractionStrength) ||
181 !numberAt(*caustics, "strength", output.causticsStrength) ||
182 !numberAt(*caustics, "scale", output.causticsScale))
184 DiagnosticCode::InvalidArgument, "missing or invalid water value", "$", {}, "graphics.water"));
185 auto valid = output.validate();
186 if (!valid) return Result<WaterStyleConfig>::failure(valid.status());
187 return Result<WaterStyleConfig>::success(std::move(output));
188}
189
191 auto value = Value::fromJson(json);
192 if (!value) return Result<WaterStyleConfig>::failure(value.status());
193 return fromValue(value.value());
194}
195
197 auto value = toValue();
198 if (!value) return Result<std::string>::failure(value.status());
199 return value.value().toJson();
200}
201
202} // namespace eve::graphics
double value
int root
Definition AnimSmr.cpp:119
std::string output
Stable, structured diagnostics shared by engine modules.
std::map< std::string, Var > values
std::string name
bool valid
std::vector< std::string > fields
Definition PlayHost.cpp:111
Lighting3DPack lighting
std::vector< float > colors
bool found
Json object
float size
Definition TreeMesh.cpp:156
std::uint32_t depth
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
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
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
const T * getIf() const
Return an immediately borrowed typed value.
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
const EditorValue * field(const EditorValue &value, const char *name)
Versioned, backend-neutral configuration for the built-in stylized water surface.
static constexpr std::string_view SchemaId
static Result< WaterStyleConfig > fromValue(const Value &value)
Decode version one transactionally; unknown fields and future versions are rejected.
static constexpr std::uint32_t SchemaVersion
Result< std::string > toJson() const
Serialize canonical JSON after validation.
Result< Value > toValue() const
Encode the canonical version-one representation. Unknown fields are rejected.
Result< void > validate() const
Validate finite values and authored ranges without mutating runtime state.
static Result< WaterStyleConfig > fromJson(std::string_view json)
Parse JSON and decode version one transactionally.
glm::vec4 color