75 if (
payload.value().chunks.size() != 1)
throw Invalid{};
79 if (!
object)
throw Invalid{};
83 auto version = integer(o,
"schemaVersion", 0);
84 if (
string(o,
"schema",
"") !=
"eve.material" ||
85 (version != 5 && version != 6 && version != 7 && version != 8 && version != 9 && version != 10 &&
86 version != 11 && version != 12 && version != 13 && version != 14 && version != 15))
88 if (version !=
payload.value().schemaVersion.value())
throw Invalid{};
89 if (version >= 15 && !o.contains(
"alphaToCoverage"))
throw Invalid{};
90 if (version == 5 && o.contains(
"vegetationSurface"))
throw Invalid{};
91 vector(o,
"motionHighlightColor",
s.motionHighlightColor);
92 if (
auto* encoded = field(o,
"vegetationSurface")) {
94 const auto expectedVegetationFields = version == 6 ? 7u : (version >= 14 ? 16u : 14u);
95 if (!vegetation || vegetation->size() != expectedVegetationFields)
throw Invalid{};
96 for (
const auto& [
key,
value] : *vegetation)
97 if (
key !=
"overlay" &&
key !=
"wetness" &&
key !=
"overlayVariation" &&
key !=
"overlayProjection" &&
98 key !=
"vertexOcclusionAlpha" &&
key !=
"invertVertexOcclusion" &&
key !=
"sourceFamily" &&
99 key !=
"colors" &&
key !=
"colorsIntensity" &&
key !=
"colorsMask" &&
key !=
"colorsVariation" &&
100 key !=
"vertexOcclusionMinimum" &&
key !=
"vertexOcclusionMaximum" &&
101 key !=
"invertVertexOcclusionColors" &&
key !=
"vertexOcclusionColor" &&
102 key !=
"backfaceNormalMode")
104 if (
string(*vegetation,
"sourceFamily",
"") !=
"tve-12")
throw Invalid{};
134 if (!std::isfinite(
value) ||
value < 0)
throw Invalid{};
137 m.vegetationSurface = result;
139 if (
auto* encoded = field(o,
"vegetationDetail")) {
140 if (version < 8)
throw Invalid{};
143 auto&
d =
s.vegetationDetail;
145 d.uvMode = integer(*
detail,
"uvMode", 0);
147 vector(*
detail,
"uvScale",
d.uvScale);
148 vector(*
detail,
"uvOffset",
d.uvOffset);
149 vector(*
detail,
"color",
d.color);
150 vector(*
detail,
"colorTwo",
d.colorTwo);
151 d.colorMode = integer(*
detail,
"colorMode", 0);
158 d.blendMode = integer(*
detail,
"blendMode", 0);
159 d.alphaMode = integer(*
detail,
"alphaMode", 1);
160 d.maskMode = integer(*
detail,
"maskMode", 0);
161 d.meshMode = integer(*
detail,
"meshMode", 0);
169 if (
auto* encoded = field(o,
"vegetationAlpha")) {
170 if (version < 9 || version > 15)
throw Invalid{};
172 if (!alpha || alpha->size() != (version < 12 ? 3u : 6u))
throw Invalid{};
173 auto&
a =
s.vegetationAlpha;
175 a.global =
number(*alpha,
"global", 1);
176 a.variation =
number(*alpha,
"variation", .5f);
177 a.detailFade =
boolean(*alpha,
"detailFade",
false);
179 a.glancing =
number(*alpha,
"glancing", 0);
180 a.camera =
number(*alpha,
"camera", 1);
181 a.constant =
number(*alpha,
"constant", 0);
184 if (
auto* encoded = field(o,
"vegetationFields")) {
185 if (version < 9 || version > 15)
throw Invalid{};
187 if (!
fields ||
fields->size() != (version == 9 ? 4u : 9u))
throw Invalid{};
188 s.vegetationColors.layer = integer(*
fields,
"colorsLayer", 0);
189 s.vegetationColors.usePivotPosition =
boolean(*
fields,
"colorsUsePivotPosition",
false);
190 s.vegetationExtras.layer = integer(*
fields,
"extrasLayer", 0);
191 s.vegetationExtras.usePivotPosition =
boolean(*
fields,
"extrasUsePivotPosition",
false);
193 s.vegetationMotion.layer = integer(*
fields,
"motionLayer", 0);
194 s.vegetationVertex.layer = integer(*
fields,
"vertexLayer", 0);
195 s.vegetationVertex.globalSize =
number(*
fields,
"globalSize", 1);
196 s.vegetationVertex.sizeFadeStart =
number(*
fields,
"sizeFadeStart", 0);
197 s.vegetationVertex.sizeFadeEnd =
number(*
fields,
"sizeFadeEnd", 100);
200 if (
auto* encoded = field(o,
"vegetationMotion")) {
201 if (version < 11 || version > 15)
throw Invalid{};
203 if (!motion || motion->size() != 21)
throw Invalid{};
204 for (
const auto& [
key,
value] : *motion)
205 if (
key !=
"dynamicMode" &&
key !=
"rigidity" &&
key !=
"facing" &&
key !=
"bending" &&
206 key !=
"bendingSpeed" &&
key !=
"bendingScale" &&
key !=
"bendingVariation" &&
key !=
"branch" &&
207 key !=
"rolling" &&
key !=
"branchSpeed" &&
key !=
"branchScale" &&
key !=
"branchVariation" &&
208 key !=
"flutter" &&
key !=
"flutterSpeed" &&
key !=
"flutterScale" &&
key !=
"flutterVariation" &&
209 key !=
"interaction" &&
key !=
"interactionMask" &&
key !=
"perspectivePush" &&
210 key !=
"perspectiveNoise" &&
key !=
"perspectiveAngle")
212 auto&
m =
s.vegetationMotion;
213 m.dynamicMode =
number(*motion,
"dynamicMode", 0);
214 m.rigidity =
number(*motion,
"rigidity", .5f);
215 m.facing =
number(*motion,
"facing", .5f);
216 m.bending =
number(*motion,
"bending", .2f);
217 m.bendingSpeed =
number(*motion,
"bendingSpeed", 2);
218 m.bendingScale =
number(*motion,
"bendingScale", 1);
219 m.bendingVariation =
number(*motion,
"bendingVariation", 0);
220 m.branch =
number(*motion,
"branch", .2f);
221 m.rolling =
number(*motion,
"rolling", .2f);
222 m.branchSpeed =
number(*motion,
"branchSpeed", 6);
223 m.branchScale =
number(*motion,
"branchScale", 3);
224 m.branchVariation =
number(*motion,
"branchVariation", 0);
225 m.flutter =
number(*motion,
"flutter", .2f);
226 m.flutterSpeed =
number(*motion,
"flutterSpeed", 20);
227 m.flutterScale =
number(*motion,
"flutterScale", 10);
228 m.flutterVariation =
number(*motion,
"flutterVariation", 0);
229 m.interaction =
number(*motion,
"interaction", 1);
230 m.interactionMask =
number(*motion,
"interactionMask", 1);
231 m.perspectivePush =
number(*motion,
"perspectivePush", 0);
232 m.perspectiveNoise =
number(*motion,
"perspectiveNoise", 0);
233 m.perspectiveAngle =
number(*motion,
"perspectiveAngle", 1);
234 if (
m.dynamicMode < 0 ||
m.dynamicMode > 1 ||
m.rigidity < 0 ||
m.rigidity > 1 ||
m.facing < 0 ||
235 m.facing > 1 ||
m.interactionMask < 0 ||
m.interactionMask > 1)
237 for (
const float value :
238 {
m.bending,
m.bendingSpeed,
m.bendingScale,
m.bendingVariation,
m.branch,
m.rolling,
m.branchSpeed,
239 m.branchScale,
m.branchVariation,
m.flutter,
m.flutterSpeed,
m.flutterScale,
m.flutterVariation,
240 m.interaction,
m.perspectivePush,
m.perspectiveNoise,
m.perspectiveAngle})
241 if (value < 0 || value > 1000000)
throw Invalid{};
243 if (
auto* encoded = field(o,
"vegetationEmission")) {
244 if (version < 13)
throw Invalid{};
246 if (!emission || emission->size() != 4)
throw Invalid{};
247 for (
const auto& [
key,
value] : *emission)
248 if (
key !=
"minimum" &&
key !=
"maximum" &&
key !=
"phase" &&
key !=
"global")
throw Invalid{};
249 auto& e =
s.vegetationEmission;
250 e.minimum =
number(*emission,
"minimum", 0);
251 e.maximum =
number(*emission,
"maximum", 1);
252 e.phase =
number(*emission,
"phase", 1);
253 e.global =
number(*emission,
"global", 1);
256 if (
auto* encoded = field(o,
"vegetationGradient")) {
257 if (version < 14)
throw Invalid{};
259 if (!gradient || gradient->size() != 4)
throw Invalid{};
260 for (
const auto& [
key,
value] : *gradient)
261 if (
key !=
"colorOne" &&
key !=
"colorTwo" &&
key !=
"minimum" &&
key !=
"maximum")
throw Invalid{};
262 auto&
g =
s.vegetationGradient;
263 vector(*gradient,
"colorOne",
g.colorOne);
264 vector(*gradient,
"colorTwo",
g.colorTwo);
265 g.minimum =
number(*gradient,
"minimum", 0);
266 g.maximum =
number(*gradient,
"maximum", 1);
269 const auto shading =
string(o,
"shadingModel",
"");
270 if (shading !=
"pbr" && shading !=
"unlit")
throw Invalid{};
271 s.unlit = shading ==
"unlit";
272 auto mode =
string(o,
"surfaceMode",
"opaque");
273 if (mode !=
"opaque" && mode !=
"masked" && mode !=
"transparent")
throw Invalid{};
274 m.transparent = mode ==
"transparent";
275 m.masked = mode ==
"masked";
277 if (
blend !=
"alpha" &&
blend !=
"premultiplied")
throw Invalid{};
278 m.blend =
blend ==
"alpha" ? graphics::BlendMode::Alpha : graphics::BlendMode::Premultiplied;
279 m.doubleSided =
boolean(o,
"doubleSided",
false);
280 const auto cullMode =
string(o,
"cullMode",
m.doubleSided ?
"none" :
"back");
281 if (cullMode !=
"none" && cullMode !=
"back" && cullMode !=
"front")
throw Invalid{};
282 if ((cullMode ==
"none") !=
m.doubleSided)
throw Invalid{};
286 s.alphaToCoverage = version >= 15 &&
boolean(o,
"alphaToCoverage",
false);
287 m.alphaCutoff =
number(o,
"alphaCutoff", .5f);
288 std::array<float, 4>
color{1, 1, 1, 1};
289 vector(o,
"baseColor",
color);
290 for (std::size_t i = 0; i <
color.size(); ++i)
291 if (
color[i] < 0 || (i == 3 &&
color[i] > 1))
throw Invalid{};
293 m.metallic =
number(o,
"metallic", 0);
294 m.roughness =
number(o,
"roughness", 1);
295 if (
m.metallic < 0 ||
m.metallic > 1 ||
m.roughness < 0 ||
m.roughness > 1 ||
m.alphaCutoff < 0 ||
298 vector(o,
"emissive",
s.emissive);
299 vector(o,
"specularColorFactor",
s.specularColor);
300 s.normalScale =
number(o,
"normalScale", 1);
301 s.occlusionStrength =
number(o,
"occlusionStrength", 1);
302 s.emissiveStrength =
number(o,
"emissiveStrength", 1);
303 s.specularFactor =
number(o,
"specularFactor", 1);
304 s.ior =
number(o,
"ior", 1.5f);
305 s.anisotropyStrength =
number(o,
"anisotropyStrength", 0);
306 s.anisotropyRotation =
number(o,
"anisotropyRotation", 0);
307 s.clearcoatFactor =
number(o,
"clearcoatFactor", 0);
308 s.clearcoatRoughness =
number(o,
"clearcoatRoughnessFactor", 0);
309 s.clearcoatNormalScale =
number(o,
"clearcoatNormalScale", 1);
310 s.albedoTextureStrength =
number(o,
"albedoTextureStrength", 1);
311 if (
auto* encoded = field(o,
"translucency")) {
313 if (!trans)
throw Invalid{};
314 for (
const auto& [
key,
value] : *trans)
315 if (
key !=
"color" &&
key !=
"intensity" &&
key !=
"strength" &&
key !=
"normalDistortion" &&
316 key !=
"scattering" &&
key !=
"direct" &&
key !=
"ambient" &&
key !=
"shadow" &&
317 key !=
"maskAmount" &&
key !=
"maskMinimum" &&
key !=
"maskMaximum")
319 auto&
t =
s.translucency;
320 vector(*trans,
"color",
t.color);
321 t.intensity =
number(*trans,
"intensity", 0);
322 t.strength =
number(*trans,
"strength", 1);
323 t.normalDistortion =
number(*trans,
"normalDistortion", .5f);
324 t.scattering =
number(*trans,
"scattering", 2);
325 t.direct =
number(*trans,
"direct", .9f);
326 t.ambient =
number(*trans,
"ambient", .1f);
327 t.shadow =
number(*trans,
"shadow", .5f);
328 t.maskAmount =
number(*trans,
"maskAmount", 0);
329 t.maskMinimum =
number(*trans,
"maskMinimum", 0);
330 t.maskMaximum =
number(*trans,
"maskMaximum", 0);
333 if (
auto* encoded = field(o,
"normalEncoding")) {
334 if (!encoded->isString())
throw Invalid{};
335 const auto&
name = encoded->asString();
336 if (
name ==
"tangent-xyz")
338 else if (
name ==
"tve-rg")
340 else if (
name ==
"tve-rag")
342 else if (
name ==
"tve-ag")
347 const bool colorMaskEnabled = o.contains(
"colorMask");
348 if (colorMaskEnabled) {
350 if (!
mask ||
mask->size() != 3 || !
mask->contains(
"secondary") || !
mask->contains(
"minimum") ||
351 !
mask->contains(
"maximum"))
353 vector(*
mask,
"secondary",
s.colorMaskSecondary);
357 constexpr const char* roles[] = {
"baseColorTexture",
"metallicRoughnessTexture",
"normalTexture",
358 "occlusionTexture",
"emissiveTexture",
"specularTexture",
359 "specularColorTexture",
"anisotropyTexture",
"clearcoatTexture",
360 "clearcoatRoughnessTexture",
"clearcoatNormalTexture"};
361 for (
size_t i = 0; i < 11; i++) {
362 std::string role = roles[i];
363 auto*
image = field(o, role);
364 if (!
image)
continue;
365 if (!
image->isString())
throw Invalid{};
368 m.images[i] = std::move(ref).takeValue();
369 auto&
b =
s.textures[i];
370 b.srgbDecode =
false;
371 b.texcoord = integer(o, role +
"TexCoord", 0);
372 if (
auto* transform = field(o, role +
"Transform")) {
374 if (!
t)
throw Invalid{};
375 vector(*
t,
"offset",
b.offset);
376 vector(*
t,
"scale",
b.scale);
377 b.rotation =
number(*
t,
"rotation", 0);
378 b.texcoord = integer(*
t,
"texCoord",
b.texcoord);
380 if (
auto*
sampler = field(o, role +
"Sampler")) {
382 if (!
t)
throw Invalid{};
383 b.wrapS = integer(*
t,
"wrapS", 10497);
384 b.wrapT = integer(*
t,
"wrapT", 10497);
385 b.minFilter = integer(*
t,
"minFilter", 9987);
386 b.magFilter = integer(*
t,
"magFilter", 9729);
389 constexpr const char* detailRoles[] = {
"detailAlbedoTexture",
"detailNormalTexture",
"detailMaskTexture"};
390 for (
size_t i = 0; i < 3; ++i) {
391 const std::string role = detailRoles[i];
392 auto*
image = field(o, role);
393 if (!
image)
continue;
394 if (version < 8 || !image->isString())
throw Invalid{};
397 m.detailImages[i] = std::move(ref).takeValue();
398 auto&
b =
s.vegetationDetail.textures[i];
399 b.srgbDecode = i == 0;
400 if (
auto*
sampler = field(o, role +
"Sampler")) {
402 if (!
t)
throw Invalid{};
403 b.wrapS = integer(*
t,
"wrapS", 10497);
404 b.wrapT = integer(*
t,
"wrapT", 10497);
405 b.minFilter = integer(*
t,
"minFilter", 9987);
406 b.magFilter = integer(*
t,
"magFilter", 9729);
409 const auto transMask =
s.translucency.maskAmount;
410 if (!std::isfinite(transMask) || transMask < 0 || transMask > 1)
throw Invalid{};
411 s.translucency.maskAmount = 0;
412 const auto detailValue =
s.vegetationDetail.value;
413 s.vegetationDetail.value = 0;
418 if (colorMaskEnabled && !
m.images[1])
throw Invalid{};
419 if (
s.translucency.intensity > 0 && transMask > 0 && !
m.images[1])
throw Invalid{};
420 s.translucency.maskAmount = transMask;
421 if (detailValue > 0 && (!
m.detailImages[0] || !
m.detailImages[1]))
throw Invalid{};
422 s.vegetationDetail.value = detailValue;
424 (!
m.images[2] ||
s.normalScale < -8.f ||
s.normalScale > 8.f))
426 if (
s.vegetationEmission.enabled && !
m.images[4])
throw Invalid{};
427 s.normalMode = normalMode;
428 s.colorMaskEnabled = colorMaskEnabled;
429 if (
m.vegetationSurface) {
430 auto& vegetation = *
m.vegetationSurface;
431 vegetation.albedo = {
m.color.r,
m.color.g,
m.color.b,
m.color.a};
432 vegetation.emission =
s.emissive;
433 vegetation.roughness =
m.roughness;
434 vegetation.alphaCutoff =
m.alphaCutoff;
437 }
catch (
const Invalid&) {