11 PropertyFlag flags = PropertyFlag::Runtime) {
14 result.displayNameKey =
label;
24 if (!
object)
return nullptr;
25 const auto found =
object->find(
key);
26 return found ==
object->end() ? nullptr : &
found->second;
32 : id_(
std::move(
id)), values_(defaults()) {}
36 result.
id = TargetId(id_);
37 result.
type =
"material-document";
54 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId(
"editor.material.target-mismatch"),
55 "Material operation targets another document");
56 if (
operation.type !=
"material.property.set.v1")
57 return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId(
"editor.material.operation-unsupported"),
58 "Unsupported material operation: " +
operation.type);
61 const auto*
path = pathValue ? pathValue->
getIf<std::string>() :
nullptr;
63 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId(
"editor.material.operation-payload"),
64 "Material operation requires path and value");
67 return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId(
"editor.material.property-unsupported"),
68 "Unknown material property: " + *
path);
74 return eve::editing::applied<void>();
78 return std::make_unique<MaterialDocumentTarget>(*
this);
82 std::unique_ptr<IDomainOperationTarget> candidate) {
84 if (!typed || typed->id_ != id_)
85 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId(
"editor.material.candidate-mismatch"),
86 "Material candidate belongs to another target");
88 return eve::editing::applied<void>();
92 if (!selectionMatches(selection))
95 "editor.material.selection", {},
"editor.MaterialDocumentTarget"));
103 if (!selectionMatches(selection))
return {};
104 const auto found = values_.find(
path.value());
105 if (
found == values_.end())
return {};
106 return {PropertyReadState::Value,
found->second, {}};
112 PropertySetMode mode)
const {
113 if (!selectionMatches(selection))
114 return eve::editing::failed<DomainOperation>(EditorStatus::Rejected, RuleId(
"editor.material.selection"),
115 "Selection does not belong to this material");
116 if (mode == PropertySetMode::Reset)
return makeReset(selection,
path);
117 if (mode != PropertySetMode::Absolute)
118 return eve::editing::failed<DomainOperation>(EditorStatus::Unsupported, RuleId(
"editor.material.set-mode"),
119 "Material properties require absolute assignment");
122 return eve::editing::failed<DomainOperation>(EditorStatus::Unsupported,
123 RuleId(
"editor.material.property-unsupported"),
124 "Unknown material property: " +
path.
value());
129 return eve::editing::failed<DomainOperation>(EditorStatus::NotFound, RuleId(
"editor.material.property-missing"),
130 "Material property has no current value");
133 object[
"path"] =
path.value();
134 object[
"value"] = assigned;
145 return eve::editing::applied<DomainOperation>(std::move(
operation));
152 return eve::editing::failed<DomainOperation>(EditorStatus::Unsupported,
153 RuleId(
"editor.material.property-unsupported"),
154 "Unknown material property: " +
path.
value());
162 root[
"schemaVersion"] = 9;
168 const EditorValue* versionValue = objectField(snapshot,
"schemaVersion");
169 const EditorValue* propertiesValue = objectField(snapshot,
"properties");
170 const auto* version = versionValue ? versionValue->
getIf<int64_t>() :
nullptr;
172 if (!version || (*version < 1 || *version > 9) || !
properties)
173 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId(
"editor.material.snapshot-format"),
174 "Material snapshot requires schemaVersion 1 through 9 and properties");
175 auto candidate = defaults();
180 return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId(
"editor.material.snapshot-property"),
181 "Material snapshot contains unknown property: " +
path);
186 values_ = std::move(candidate);
189 return eve::editing::applied<void>();
193 std::vector<EditorDiagnostic> diagnostics;
194 const auto stringValue = [&](
const char*
path) -> std::string {
196 if (
found == values_.end())
return {};
197 const auto*
value =
found->second.getIf<std::string>();
200 if (stringValue(
"shading.model") ==
"custom" && stringValue(
"textures.shader").empty())
203 DiagnosticSeverity::Error,
"Custom shading requires a shader asset"));
204 if (stringValue(
"surface.mode") ==
"masked" && stringValue(
"textures.albedo").empty())
207 DiagnosticSeverity::Warning,
"Masked material has no albedo texture providing alpha"));
208 if (!stringValue(
"textures.height").empty()) {
209 const auto*
scale = values_.at(
"parallax.scale").getIf<
double>();
213 DiagnosticSeverity::Info,
"Height texture is assigned while parallax scale is zero"));
215 const auto boolValue = [&](
const char*
path) {
217 const auto*
value =
found == values_.end() ? nullptr :
found->second.getIf<
bool>();
220 if (boolValue(
"vegetation.alpha.enabled") && stringValue(
"vegetation.alpha.noise").empty())
223 DiagnosticSeverity::Warning,
224 "Vegetation alpha fading uses the neutral noise volume until a 3D noise asset is assigned"));
230 schema.
typeId =
"graphics.material";
232 auto shading = property(
"shading.model",
"editor.material.shading-model",
"shading",
233 PropertyType::Enum,
"pbr");
234 shading.enumItems = {
"pbr",
"unlit",
"hair",
"custom"};
235 schema.
properties.push_back(std::move(shading));
236 auto tint = property(
"shading.tint",
"editor.material.tint",
"shading", PropertyType::Color,
246 numeric(
"shading.metallic",
"editor.material.metallic", 0.0, 0.0, 1.0);
247 numeric(
"shading.roughness",
"editor.material.roughness", 0.45, 0.04, 1.0);
248 for (
const auto& [
path,
label] : {std::pair{
"textures.albedo",
"editor.material.albedo"},
249 {
"textures.normal",
"editor.material.normal"},
250 {
"textures.height",
"editor.material.height"},
251 {
"textures.orm",
"editor.material.orm"},
252 {
"textures.emissive",
"editor.material.emissive"},
253 {
"textures.shader",
"editor.material.shader"}}) {
255 descriptor.assetTypeFilters =
path == std::string(
"textures.shader")
256 ? std::vector<std::string>{
"shader"}
257 : std::vector<std::string>{
"texture"};
260 auto surface = property(
"surface.mode",
"editor.material.surface-mode",
"surface",
261 PropertyType::Enum,
"opaque");
262 surface.enumItems = {
"opaque",
"masked",
"transparent"};
263 schema.
properties.push_back(std::move(surface));
264 auto blend = property(
"surface.blend",
"editor.material.blend-mode",
"surface",
265 PropertyType::Enum,
"alpha");
266 blend.enumItems = {
"alpha",
"premultiplied",
"additive",
"multiply"};
268 numeric(
"surface.alpha-cutoff",
"editor.material.alpha-cutoff", 0.5, 0.0, 1.0);
269 numeric(
"parallax.scale",
"editor.material.parallax-scale", 0.0, 0.0, 0.25);
271 std::tuple{
"surface.depth-write",
"editor.material.depth-write",
false},
272 {
"surface.double-sided",
"editor.material.double-sided",
false},
273 {
"lighting.receive",
"editor.material.receive-light",
true},
274 {
"shadow.cast",
"editor.material.cast-shadow",
true},
275 {
"shadow.receive",
"editor.material.receive-shadow",
true}})
277 schema.
properties.push_back(property(
"vegetation.alpha.enabled",
"editor.material.vegetation-alpha-enabled",
278 "vegetation-alpha", PropertyType::Bool,
false));
279 auto fadeNoise = property(
"vegetation.alpha.noise",
"editor.material.vegetation-alpha-noise",
280 "vegetation-alpha", PropertyType::AssetRef,
"");
281 fadeNoise.assetTypeFilters = {
"texture3d"};
282 schema.
properties.push_back(std::move(fadeNoise));
290 vegetationNumeric(
"vegetation.alpha.global",
"editor.material.vegetation-alpha-global", 0.0, 0.0, 1.0);
291 vegetationNumeric(
"vegetation.alpha.variation",
"editor.material.vegetation-alpha-variation", 0.0, 0.0, 1.0);
292 vegetationNumeric(
"vegetation.alpha.glancing",
"editor.material.vegetation-alpha-glancing", 0.0, 0.0, 1.0);
293 vegetationNumeric(
"vegetation.alpha.camera",
"editor.material.vegetation-alpha-camera", 1.0, 0.0, 1.0);
294 vegetationNumeric(
"vegetation.alpha.constant",
"editor.material.vegetation-alpha-constant", 0.0, 0.0, 1.0);
295 vegetationNumeric(
"vegetation.alpha.camera-min",
"editor.material.vegetation-alpha-camera-min", 0.0, 0.0,
297 vegetationNumeric(
"vegetation.alpha.camera-max",
"editor.material.vegetation-alpha-camera-max", 100.0, 0.0,
299 vegetationNumeric(
"vegetation.alpha.noise-tiling",
"editor.material.vegetation-alpha-noise-tiling", 1.0, 0.0,
301 schema.
properties.push_back(property(
"vegetation.alpha.detail-fade",
302 "editor.material.vegetation-alpha-detail-fade",
"vegetation-alpha",
303 PropertyType::Bool,
false));
304 schema.
properties.push_back(property(
"vegetation.emission.enabled",
"editor.material.vegetation-emission-enabled",
305 "vegetation-emission", PropertyType::Bool,
false));
306 auto vegetationStageNumeric = [&](
const char*
path,
const char*
label,
const char*
category,
double value) {
313 vegetationStageNumeric(
"vegetation.emission.minimum",
"editor.material.vegetation-emission-minimum",
314 "vegetation-emission", 0.0);
315 vegetationStageNumeric(
"vegetation.emission.maximum",
"editor.material.vegetation-emission-maximum",
316 "vegetation-emission", 1.0);
317 vegetationStageNumeric(
"vegetation.emission.phase",
"editor.material.vegetation-emission-phase",
318 "vegetation-emission", 1.0);
319 vegetationStageNumeric(
"vegetation.emission.global",
"editor.material.vegetation-emission-global",
320 "vegetation-emission", 1.0);
321 schema.
properties.push_back(property(
"vegetation.gradient.enabled",
"editor.material.vegetation-gradient-enabled",
322 "vegetation-gradient", PropertyType::Bool,
false));
323 schema.
properties.push_back(property(
"vegetation.gradient.color-one",
"editor.material.vegetation-gradient-color-one",
324 "vegetation-gradient", PropertyType::Color,
326 schema.
properties.push_back(property(
"vegetation.gradient.color-two",
"editor.material.vegetation-gradient-color-two",
327 "vegetation-gradient", PropertyType::Color,
329 vegetationStageNumeric(
"vegetation.gradient.minimum",
"editor.material.vegetation-gradient-minimum",
330 "vegetation-gradient", 0.0);
331 vegetationStageNumeric(
"vegetation.gradient.maximum",
"editor.material.vegetation-gradient-maximum",
332 "vegetation-gradient", 1.0);
333 schema.
properties.push_back(property(
"vegetation.translucency.enabled",
334 "editor.material.vegetation-translucency-enabled",
335 "vegetation-translucency", PropertyType::Bool,
false));
336 schema.
properties.push_back(property(
"vegetation.translucency.color",
337 "editor.material.vegetation-translucency-color",
338 "vegetation-translucency", PropertyType::Color,
341 const std::string
path = std::string(
"vegetation.translucency.") +
name;
342 const std::string
label = std::string(
"editor.material.vegetation-translucency-") +
name;
349 translucencyNumeric(
"intensity", 0.0, 0.0, 1.0);
350 translucencyNumeric(
"strength", 1.0, 0.0, 50.0);
351 translucencyNumeric(
"normal-distortion", 0.5, 0.0, 1.0);
352 translucencyNumeric(
"scattering", 2.0, 1.0, 50.0);
353 translucencyNumeric(
"direct", 0.9, 0.0, 1.0);
354 translucencyNumeric(
"ambient", 0.1, 0.0, 1.0);
355 translucencyNumeric(
"shadow", 0.5, 0.0, 1.0);
356 translucencyNumeric(
"mask-amount", 0.0, 0.0, 1.0);
357 translucencyNumeric(
"global", 1.0, 0.0, 1000000.0);
358 translucencyNumeric(
"overlay", 1.0, 0.0, 1000000.0);
359 translucencyNumeric(
"mask-minimum", 0.0, 0.0, 1.0);
360 translucencyNumeric(
"mask-maximum", 0.0, 0.0, 1.0);
361 schema.
properties.push_back(property(
"vegetation.color.enabled",
"editor.material.vegetation-color-enabled",
362 "vegetation-color", PropertyType::Bool,
false));
364 std::tuple{
"vegetation.color.field",
"editor.material.vegetation-field-color",
366 {
"vegetation.color.overlay-color",
"editor.material.vegetation-overlay-color",
368 {
"vegetation.color.vertex-occlusion-color",
"editor.material.vegetation-vertex-occlusion-color",
372 const std::string
path = std::string(
"vegetation.color.") +
name;
373 const std::string
label = std::string(
"editor.material.vegetation-color-") +
name;
381 std::pair{
"overlay", 0.0}, {
"wetness", 0.0}, {
"overlay-variation", 0.5},
382 {
"overlay-projection", 0.5}, {
"vertex-occlusion-alpha", 0.5019608},
383 {
"overlay-normal", 0.5}, {
"wetness-normal", 0.5}, {
"overlay-smoothness", 0.5},
384 {
"wetness-contrast", 0.5}, {
"overlay-subsurface", 0.5}, {
"colors-coverage", 1.0},
385 {
"colors-mask", 1.0}, {
"colors-variation", 0.5}, {
"color-mask-minimum", 0.1},
386 {
"color-mask-maximum", 0.2}, {
"overlay-mask-minimum", 0.1}, {
"overlay-mask-maximum", 0.2},
387 {
"vertex-occlusion-minimum", 0.0}, {
"vertex-occlusion-maximum", 1.0}})
389 colorNumeric(
"colors-intensity", 1.0, 0.0, 2.0);
390 colorNumeric(
"alpha-threshold-offset", 0.0, -0.5, 0.5);
391 schema.
properties.push_back(property(
"vegetation.color.invert-vertex-occlusion",
392 "editor.material.vegetation-color-invert-vertex-occlusion",
393 "vegetation-color", PropertyType::Bool,
false));
394 schema.
properties.push_back(property(
"vegetation.color.invert-vertex-occlusion-colors",
395 "editor.material.vegetation-color-invert-vertex-occlusion-colors",
396 "vegetation-color", PropertyType::Bool,
false));
397 auto backface = property(
"vegetation.color.backface-normal",
"editor.material.vegetation-backface-normal",
398 "vegetation-color", PropertyType::Enum,
"flip");
399 backface.enumItems = {
"flip",
"mirror",
"same"};
400 schema.
properties.push_back(std::move(backface));
401 schema.
properties.push_back(property(
"vegetation.detail.enabled",
"editor.material.vegetation-detail-enabled",
402 "vegetation-detail", PropertyType::Bool,
false));
404 std::pair{
"vegetation.detail.albedo",
"editor.material.vegetation-detail-albedo"},
405 {
"vegetation.detail.normal",
"editor.material.vegetation-detail-normal"},
406 {
"vegetation.detail.mask",
"editor.material.vegetation-detail-mask"}}) {
412 schema.
properties.push_back(property(
"vegetation.detail.color",
"editor.material.vegetation-detail-color",
413 "vegetation-detail", PropertyType::Color,
415 schema.
properties.push_back(property(
"vegetation.detail.color-two",
"editor.material.vegetation-detail-color-two",
416 "vegetation-detail", PropertyType::Color,
418 schema.
properties.push_back(property(
"vegetation.detail.uv-scale",
"editor.material.vegetation-detail-uv-scale",
419 "vegetation-detail", PropertyType::Vec2,
421 schema.
properties.push_back(property(
"vegetation.detail.uv-offset",
"editor.material.vegetation-detail-uv-offset",
422 "vegetation-detail", PropertyType::Vec2,
424 schema.
properties.push_back(property(
"vegetation.detail.inverse-uv-scale",
425 "editor.material.vegetation-detail-inverse-uv-scale",
426 "vegetation-detail", PropertyType::Bool,
false));
428 const std::string
path = std::string(
"vegetation.detail.") +
name;
429 const std::string
label = std::string(
"editor.material.vegetation-detail-") +
name;
430 auto descriptor = property(
path.c_str(),
label.c_str(),
"vegetation-detail", PropertyType::Enum,
435 detailEnum(
"uv-mode", {
"primary",
"detail",
"world"},
"primary");
436 detailEnum(
"color-mode", {
"single",
"variation"},
"single");
437 detailEnum(
"blend-mode", {
"multiply",
"replace"},
"multiply");
438 detailEnum(
"alpha-mode", {
"main",
"detail"},
"detail");
439 detailEnum(
"mask-mode", {
"regular",
"inverse"},
"regular");
440 detailEnum(
"mesh-mode", {
"regular",
"inverse"},
"regular");
442 const std::string
path = std::string(
"vegetation.detail.") +
name;
443 const std::string
label = std::string(
"editor.material.vegetation-detail-") +
name;
450 detailNumeric(
"value", 1.0, 0.0, 1.0);
451 detailNumeric(
"normal-value", 1.0, -8.0, 8.0);
453 std::pair{
"normal-blend", 1.0}, {
"albedo-value", 1.0}, {
"metallic", 0.0}, {
"occlusion", 1.0},
454 {
"smoothness", 1.0}, {
"blend-minimum", 0.0}, {
"blend-maximum", 1.0}, {
"mask-minimum", 0.0},
455 {
"mask-maximum", 1.0}, {
"mesh-minimum", 0.0}, {
"mesh-maximum", 1.0}})
458 const std::string prefix = std::string(
"vegetation.") +
group;
459 const std::string
label = std::string(
"editor.material.vegetation-") +
group;
460 schema.
properties.push_back(property((prefix +
".enabled").c_str(), (
label +
"-enabled").c_str(),
461 "vegetation-fields", PropertyType::Bool,
false));
462 auto texture = property((prefix +
".texture").c_str(), (
label +
"-texture").c_str(),
463 "vegetation-fields", PropertyType::AssetRef,
EditorValue(std::string{}));
464 texture.assetTypeFilters = {
"texture2d-array"};
465 schema.
properties.push_back(std::move(texture));
466 auto layer = property((prefix +
".layer").c_str(), (
label +
"-layer").c_str(),
467 "vegetation-fields", PropertyType::Int, std::int64_t(0));
468 layer.numeric.minimum = 0;
469 layer.numeric.maximum = 8;
470 layer.numeric.step = 1;
472 schema.
properties.push_back(property((prefix +
".fallback").c_str(), (
label +
"-fallback").c_str(),
473 "vegetation-fields", PropertyType::Vec4, std::move(fallback)));
474 schema.
properties.push_back(property((prefix +
".coords").c_str(), (
label +
"-coords").c_str(),
475 "vegetation-fields", PropertyType::Vec4,
477 schema.
properties.push_back(property((prefix +
".use-pivot-position").c_str(),
478 (
label +
"-use-pivot-position").c_str(),
"vegetation-fields",
479 PropertyType::Bool,
false));
480 for (std::int64_t i = 0; i < 9; ++i) {
481 const std::string
path = prefix +
".usage-" + std::to_string(i);
482 auto usage = property(
path.c_str(), (
label +
"-usage").c_str(),
"vegetation-fields",
483 PropertyType::Float, 0.0);
484 usage.numeric.minimum = 0.0;
485 usage.numeric.maximum = 1.0;
486 usage.numeric.step = 0.01;
492 schema.
properties.push_back(property(
"vegetation.vertex.enabled",
"editor.material.vegetation-vertex-enabled",
493 "vegetation-vertex", PropertyType::Bool,
false));
494 auto vertexTexture = property(
"vegetation.vertex.texture",
"editor.material.vegetation-vertex-texture",
495 "vegetation-vertex", PropertyType::AssetRef,
EditorValue(std::string{}));
496 vertexTexture.assetTypeFilters = {
"texture2d-array"};
497 schema.
properties.push_back(std::move(vertexTexture));
498 auto vertexLayer = property(
"vegetation.vertex.layer",
"editor.material.vegetation-vertex-layer",
499 "vegetation-vertex", PropertyType::Int, std::int64_t(0));
500 vertexLayer.numeric.minimum = 0;
501 vertexLayer.numeric.maximum = 8;
502 vertexLayer.numeric.step = 1;
503 schema.
properties.push_back(std::move(vertexLayer));
504 schema.
properties.push_back(property(
"vegetation.vertex.fallback",
"editor.material.vegetation-vertex-fallback",
505 "vegetation-vertex", PropertyType::Vec4,
507 schema.
properties.push_back(property(
"vegetation.vertex.coords",
"editor.material.vegetation-vertex-coords",
508 "vegetation-vertex", PropertyType::Vec4,
510 for (std::int64_t i = 0; i < 9; ++i) {
511 const std::string
path =
"vegetation.vertex.usage-" + std::to_string(i);
512 auto usage = property(
path.c_str(),
"editor.material.vegetation-vertex-usage",
"vegetation-vertex",
513 PropertyType::Float, 0.0);
514 usage.numeric.minimum = 0.0;
515 usage.numeric.maximum = 1.0;
516 usage.numeric.step = 0.01;
519 auto vertexSource = property(
"vegetation.vertex.source",
"editor.material.vegetation-vertex-source",
520 "vegetation-vertex", PropertyType::Enum,
"rest-mesh");
521 vertexSource.enumItems = {
"rest-mesh",
"cpu-deformed",
"gpu-fields"};
522 schema.
properties.push_back(std::move(vertexSource));
524 const std::string
path = std::string(
"vegetation.vertex.") +
name;
525 const std::string
label = std::string(
"editor.material.vegetation-vertex-") +
name;
526 auto descriptor = property(
path.c_str(),
label.c_str(),
"vegetation-vertex", PropertyType::Float,
533 vertexNumeric(
"global-size", 1.0, 0.0, 1.0);
534 vertexNumeric(
"size-fade-start", 0.0, 0.0, 1000000.0);
535 vertexNumeric(
"size-fade-end", 100.0, 0.0, 1000000.0);
536 vertexNumeric(
"distance-fade-bias", 1.0, 0.0001, 1000000.0);
537 auto motionMode = property(
"vegetation.motion.mode",
"editor.material.vegetation-motion-mode",
538 "vegetation-motion", PropertyType::Enum,
"disabled");
539 motionMode.enumItems = {
"disabled",
"object"};
540 schema.
properties.push_back(std::move(motionMode));
542 std::pair{
"texture",
"texture2d-array"}, {
"noise",
"texture2d"}}) {
543 const std::string
path = std::string(
"vegetation.motion.") +
name;
544 const std::string
label = std::string(
"editor.material.vegetation-motion-") +
name;
545 auto texture = property(
path.c_str(),
label.c_str(),
"vegetation-motion", PropertyType::AssetRef,
547 texture.assetTypeFilters = {
filter};
548 schema.
properties.push_back(std::move(texture));
550 auto motionLayer = property(
"vegetation.motion.layer",
"editor.material.vegetation-motion-layer",
551 "vegetation-motion", PropertyType::Int, std::int64_t(0));
552 motionLayer.numeric.minimum = 0;
553 motionLayer.numeric.maximum = 8;
554 motionLayer.numeric.step = 1;
555 schema.
properties.push_back(std::move(motionLayer));
556 schema.
properties.push_back(property(
"vegetation.motion.fallback",
"editor.material.vegetation-motion-fallback",
557 "vegetation-motion", PropertyType::Vec4,
559 schema.
properties.push_back(property(
"vegetation.motion.coords",
"editor.material.vegetation-motion-coords",
560 "vegetation-motion", PropertyType::Vec4,
562 schema.
properties.push_back(property(
"vegetation.motion.global-direction",
563 "editor.material.vegetation-motion-global-direction",
"vegetation-motion",
565 schema.
properties.push_back(property(
"vegetation.motion.world-origin",
566 "editor.material.vegetation-motion-world-origin",
"vegetation-motion",
568 for (std::int64_t i = 0; i < 9; ++i) {
569 const std::string
path =
"vegetation.motion.usage-" + std::to_string(i);
570 auto usage = property(
path.c_str(),
"editor.material.vegetation-motion-usage",
"vegetation-motion",
571 PropertyType::Float, 0.0);
572 usage.numeric.minimum = 0.0;
573 usage.numeric.maximum = 1.0;
574 usage.numeric.step = 0.01;
578 const std::string
path = std::string(
"vegetation.motion.") +
name;
579 const std::string
label = std::string(
"editor.material.vegetation-motion-") +
name;
580 auto descriptor = property(
path.c_str(),
label.c_str(),
"vegetation-motion", PropertyType::Float,
587 motionNumeric(
"time", 0.0, -1000000000000.0, 1000000000000.0);
589 std::pair{
"dynamic-mode", 0.0}, {
"rigidity", 0.5}, {
"facing", 0.5}, {
"interaction-mask", 1.0}})
592 std::pair{
"bending", 0.2}, {
"bending-speed", 2.0}, {
"bending-scale", 1.0},
593 {
"bending-variation", 0.0}, {
"branch", 0.2}, {
"rolling", 0.2}, {
"branch-speed", 6.0},
594 {
"branch-scale", 3.0}, {
"branch-variation", 0.0}, {
"flutter", 0.2}, {
"flutter-speed", 20.0},
595 {
"flutter-scale", 10.0}, {
"flutter-variation", 0.0}, {
"global-bending", 1.0},
596 {
"global-branch", 1.0}, {
"global-flutter", 1.0}, {
"noise-tiling", 1.0},
597 {
"interaction", 1.0}, {
"fade-distance", 100.0}, {
"perspective-push", 0.0},
598 {
"perspective-noise", 0.0}, {
"perspective-angle", 1.0}})
599 motionNumeric(
name,
value, 0.0, 1000000.0);
603std::map<std::string, EditorValue> MaterialDocumentTarget::defaults() {
604 std::map<std::string, EditorValue> result;
610Result<void> MaterialDocumentTarget::validateAssignment(
const PropertyDescriptor&
descriptor,
615bool MaterialDocumentTarget::selectionMatches(
const SelectionSnapshot& selection)
const {
616 if (selection.items.size() != 1)
return false;
617 return selection.items.front().target ==
TargetId(id_);
ActionParameterOperation operation
building::EdgeCurveGroup group
std::array< float, 3 > scale
std::map< std::string, PropertyRule > properties
std::set< std::string > choices
graphics::Canvas * previous
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.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
void bumpRevision()
Advance the revision without touching the dirty region.
Revision revisionValue() const noexcept
Return the revision as the shared protocol revision type.
void widenDirty()
Mark an unknown area dirty without advancing the revision.
eve::OptionalRef< C > capability()
Query a capability through its interface-owned stable identity.
virtual void clearDirtyRegion()=0
Clears dirty region.
Optional capability exposing a deterministic, persistence-safe editing snapshot.
static CapabilityId editingCapabilityId()
Stable capability identity shared by every editable domain target.
UI-independent property access for an immutable selection snapshot.
static CapabilityId editingCapabilityId()
Stable capability identity for generic property editing.
Dotted property path (layout.size) compared and persisted as text.
Deterministic owning value tree shared by authoring hosts.
std::vector< Value > Array
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
UI-neutral, serializable material authoring target.
TargetDescriptor describe() const override
Describe.
PropertySchema schema(const SelectionSnapshot &selection) const override
Schema.
PropertyReadResult read(const SelectionSnapshot &selection, const PropertyPath &path) const override
Reads .
std::vector< EditorDiagnostic > validate() const
Validate cross-field authoring rules without mutating the target.
eve::Result< eve::Revision > currentRevision(const SelectionSnapshot &selection) const override
Current revision.
void * queryCapability(const CapabilityId &capability) override
Query an optional target capability.
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
EditorValue snapshotValue() const override
Capture deterministic content suitable for DocumentService persistence.
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
MaterialDocumentTarget(std::string id)
Material document target.
Result< DomainOperation > makeReset(const SelectionSnapshot &selection, const PropertyPath &path) const override
Make reset.
Result< DomainOperation > makeSet(const SelectionSnapshot &selection, const PropertyPath &path, const EditorValue &value, PropertySetMode mode) const override
Make set.
Result< void > loadSnapshot(const EditorValue &snapshot)
Replace content when opening a persisted material document.
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
const char * defaultValue
editing::PropertyDescriptor PropertyDescriptor
editing::PropertyPath PropertyPath
editing::TargetId TargetId
Result< void > validatePropertyValue(const PropertyDescriptor &descriptor, const Value &value)
Validate property value.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
editing::Value EditorValue
DomainOperation public API.
PropertyReadResult public API.
EVENGINE_API_PLATFORM public API.
std::vector< PropertyDescriptor > properties
PropertyDescriptorLookup find(const PropertyPath &path) const
Finds find.
SelectionSnapshot public API.
Stable discovery metadata exposed by every editable target.
std::vector< CapabilityId > capabilities