载入中...
搜索中...
未找到
DecalTarget.cpp
浏览该文件的文档.
12PropertyDescriptor prop(const char*path,PropertyType type,EditorValue value,const char*category,double min=0,double max=0,bool ranged=false,std::vector<std::string> enumItems={}){PropertyDescriptor d;d.path=PropertyPath(path);d.displayNameKey=std::string("editor.decal.")+path;d.category=category;d.type=type;d.flags=PropertyFlag::Runtime;d.defaultValue=std::move(value);if(type==PropertyType::Enum)d.enumItems=enumItems.empty()?std::vector<std::string>{"over","add"}:std::move(enumItems);if(ranged){d.numeric.minimum=min;d.numeric.maximum=max;}return d;}
13const EditorValue* field(const EditorValue&v,const std::string&k){const auto*o=v.getIf<EditorValue::Object>();if(!o)return nullptr;auto i=o->find(k);return i==o->end()?nullptr:&i->second;}
14bool hasError(const std::vector<EditorDiagnostic>&d){return std::any_of(d.begin(),d.end(),[](const auto&v){return v.severity()==DiagnosticSeverity::Error;});}
16 return eve::editing::ruleDiagnostic(eve::DiagnosticCode::PreconditionViolation, RuleId(rule), severity,
21PropertySchema DecalDocumentTarget::decalSchema(){PropertySchema s;s.typeId="decal.instance";s.properties={
22 prop("transform.position",PropertyType::Vec3,EditorValue::Array{0.0,0.0,0.0},"transform"),prop("transform.normal",PropertyType::Vec3,EditorValue::Array{0.0,1.0,0.0},"transform"),prop("transform.yaw",PropertyType::Float,0.0,"transform"),
23 prop("projection.size",PropertyType::Float,0.5,"projection",0.0001,100000,true),prop("projection.depth",PropertyType::Float,0.15,"projection",0.0001,100000,true),prop("projection.mode",PropertyType::Enum,"planar","projection",0,0,false,{"planar","triplanar","spherical","world"}),prop("projection.blendSharpness",PropertyType::Float,4.0,"projection",0.1,64,true),prop("projection.parallaxScale",PropertyType::Float,0.0,"projection",0,1,true),prop("projection.parallaxMinLayers",PropertyType::Float,8.0,"projection",1,64,true),prop("projection.parallaxMaxLayers",PropertyType::Float,24.0,"projection",1,64,true),prop("projection.edgeFadeWidth",PropertyType::Float,0.06,"projection",0,0.49,true),prop("decal.kind",PropertyType::String,"default","decal"),
24 prop("texture.albedo",PropertyType::AssetRef,"","textures"),prop("texture.normal",PropertyType::AssetRef,"","textures"),prop("texture.params",PropertyType::AssetRef,"","textures"),prop("texture.uvRect",PropertyType::Vec4,EditorValue::Array{0.0,0.0,1.0,1.0},"textures"),
25 prop("channel.normal",PropertyType::Float,0.0,"channels",0,1,true),prop("channel.roughness",PropertyType::Float,0.0,"channels",-1,1,true),prop("channel.metal",PropertyType::Float,0.0,"channels",-1,1,true),prop("channel.emissive",PropertyType::Float,0.0,"channels",0,1000,true),prop("blend.mode",PropertyType::Enum,"over","channels",0,0,false,{"over","add"}),
26 prop("lifetime.seconds",PropertyType::Float,0.0,"lifetime",0,1000000,true),prop("lifetime.fadeIn",PropertyType::Float,0.0,"lifetime",0,1000000,true),prop("lifetime.fadeOut",PropertyType::Float,0.0,"lifetime",0,1000000,true)};return s;}
27std::map<std::string,EditorValue> DecalDocumentTarget::defaults(){std::map<std::string,EditorValue>v;for(const auto&p:decalSchema().properties)v.emplace(p.path.value(),p.defaultValue);return v;}
30 return {TargetId(id_), "decal", revisionValue(), false, {CapabilityId("eve.editor.target.decal-properties")}};
32void*DecalDocumentTarget::queryCapability(const CapabilityId&c){return c==CapabilityId("eve.editor.target.decal-properties")?static_cast<IPropertyProvider*>(this):nullptr;}
33bool DecalDocumentTarget::matches(const SelectionSnapshot&s)const{return s.items.size()==1&&s.items.front().target==TargetId(id_);}
41PropertyReadResult DecalDocumentTarget::read(const SelectionSnapshot&s,const PropertyPath&p)const{if(!matches(s))return{};auto i=values_.find(p.value());return i==values_.end()?PropertyReadResult{}:PropertyReadResult{PropertyReadState::Value,i->second,{}};}
42const EditorValue*DecalDocumentTarget::value(const std::string&p)const{auto i=values_.find(p);return i==values_.end()?nullptr:&i->second;}
43Result<DomainOperation>DecalDocumentTarget::makeSet(const SelectionSnapshot&s,const PropertyPath&p,const EditorValue&v,PropertySetMode m)const{if(m==PropertySetMode::Reset)return makeReset(s,p);auto d=decalSchema().find(p);if(!matches(s)||!d||m!=PropertySetMode::Absolute)return eve::editing::failed<DomainOperation>(EditorStatus::Rejected, RuleId("editor.decal.set"), "Decal property requires a matching absolute edit");auto checked=validatePropertyValue(*d,v);if(!checked.ok())return Result<DomainOperation>::failure(checked.status());auto candidate=*this;candidate.values_[p.value()]=v;if(hasError(candidate.validate()))return eve::editing::failed<DomainOperation>(EditorStatus::Rejected, RuleId("editor.decal.invalid"), "Decal property conflicts with projection rules");DomainOperation op;op.type="decal.properties.replace.v1";op.inverseType=op.type;op.target=TargetId(id_);op.payload=EditorValue::Object{{"values",EditorValue::Object(candidate.values_.begin(),candidate.values_.end())}};op.inverse=EditorValue::Object{{"values",EditorValue::Object(values_.begin(),values_.end())}};op.hasInverse=true;op.affectedProperties.push_back(p.value());op.mergeKey="decal:"+id_+":"+p.value();return eve::editing::applied<DomainOperation>(std::move(op));}
44Result<DomainOperation>DecalDocumentTarget::makeReset(const SelectionSnapshot&s,const PropertyPath&p)const{auto d=decalSchema().find(p);if(!d)return eve::editing::failed<DomainOperation>(EditorStatus::Unsupported, RuleId("editor.decal.property"), "Unknown decal property");return makeSet(s,p,d->defaultValue,PropertySetMode::Absolute);}
47 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.operation"), "Decal operation mismatch");
50 if (!o) return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.payload"), "Decal operation payload is invalid");
56 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.unknown"), "Decal payload contains an unknown property");
58 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.value"), "Decal payload contains an invalid property value");
61 if (candidate.values_.size() != decalSchema().properties.size() || hasError(candidate.validate()))
68std::unique_ptr<IDomainOperationTarget>DecalDocumentTarget::cloneDomainState()const{return std::make_unique<DecalDocumentTarget>(*this);}
69Result<void>DecalDocumentTarget::commitDomainState(std::unique_ptr<IDomainOperationTarget>candidate){auto*t=dynamic_cast<DecalDocumentTarget*>(candidate.get());if(!t||t->id_!=id_)return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.decal.candidate"), "Decal candidate mismatch");*this=*t;return eve::editing::applied<void>();}
70std::vector<EditorDiagnostic>DecalDocumentTarget::validate()const{std::vector<EditorDiagnostic>d;const auto&normal=*value("transform.normal")->getIf<EditorValue::Array>();double length2=0;for(const auto&v:normal){const auto*n=v.getIf<double>();if(!n||!std::isfinite(*n)){d.push_back(diagnostic("editor.decal.normal",DiagnosticSeverity::Error,"Decal normal must be finite Vec3"));return d;}length2+=*n**n;}if(length2<1e-12)d.push_back(diagnostic("editor.decal.zero-normal",DiagnosticSeverity::Error,"Decal projection normal must be non-zero"));const auto&uv=*value("texture.uvRect")->getIf<EditorValue::Array>();if(uv.size()!=4)d.push_back(diagnostic("editor.decal.uv",DiagnosticSeverity::Error,"Decal UV rect must have four components"));else{double n[4];for(int i=0;i<4;++i){const auto*v=uv[i].getIf<double>();if(!v||!std::isfinite(*v)){d.push_back(diagnostic("editor.decal.uv",DiagnosticSeverity::Error,"Decal UV rect must be finite"));return d;}n[i]=*v;}if(n[0]<0||n[1]<0||n[2]<=0||n[3]<=0||n[0]+n[2]>1||n[1]+n[3]>1)d.push_back(diagnostic("editor.decal.uv-range",DiagnosticSeverity::Error,"Decal UV rect must stay within normalized atlas bounds"));}const auto&blend=*value("blend.mode")->getIf<std::string>();if(blend!="over"&&blend!="add")d.push_back(diagnostic("editor.decal.blend",DiagnosticSeverity::Error,"Decal blend mode must be over or add"));const auto&proj=*value("projection.mode")->getIf<std::string>();if(proj!="planar"&&proj!="triplanar"&&proj!="spherical"&&proj!="world")d.push_back(diagnostic("editor.decal.projection",DiagnosticSeverity::Error,"Decal projection mode must be planar, triplanar, spherical, or world"));const double sharpness=*value("projection.blendSharpness")->getIf<double>();if(!std::isfinite(sharpness)||sharpness<=0.0)d.push_back(diagnostic("editor.decal.sharpness",DiagnosticSeverity::Error,"Decal blend sharpness must be finite and positive"));const double minLayers=*value("projection.parallaxMinLayers")->getIf<double>();const double maxLayers=*value("projection.parallaxMaxLayers")->getIf<double>();if(minLayers>maxLayers)d.push_back(diagnostic("editor.decal.parallax-layers",DiagnosticSeverity::Error,"Decal POM minimum layers must not exceed maximum layers"));if(value("decal.kind")->getIf<std::string>()->empty())d.push_back(diagnostic("editor.decal.kind",DiagnosticSeverity::Error,"Decal kind must not be empty"));if(*value("texture.albedo")->getIf<std::string>()=="")d.push_back(diagnostic("editor.decal.albedo",DiagnosticSeverity::Warning,"Decal has no albedo texture"));if(blend=="add"&&*value("channel.emissive")->getIf<double>()<=0)d.push_back(diagnostic("editor.decal.additive-emissive",DiagnosticSeverity::Warning,"Additive decal has zero emissive strength"));if(*value("lifetime.seconds")->getIf<double>()==0.0&&(*value("lifetime.fadeIn")->getIf<double>()>0.0||*value("lifetime.fadeOut")->getIf<double>()>0.0))d.push_back(diagnostic("editor.decal.persistent-fade",DiagnosticSeverity::Warning,"Persistent decal fade settings have no expiry endpoint"));return d;}
71EditorValue DecalDocumentTarget::snapshotValue()const{return EditorValue::Object{{"schemaVersion",int64_t{4}},{"values",EditorValue::Object(values_.begin(),values_.end())}};}
72Result<void>DecalDocumentTarget::loadSnapshot(const EditorValue&s){const auto*v=field(s,"schemaVersion"),*values=field(s,"values");const auto*version=v?v->getIf<int64_t>():nullptr;const auto*object=values?values->getIf<EditorValue::Object>():nullptr;if(!version||(*version!=1&&*version!=2&&*version!=3&&*version!=4)||!object)return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId("editor.decal.snapshot"), "Unsupported decal snapshot");EditorValue::Object migrated=*object;const auto baseline=defaults();if(*version<4){for(const char*key:{"projection.parallaxScale","projection.parallaxMinLayers","projection.parallaxMaxLayers","projection.edgeFadeWidth"})if(!migrated.contains(key))migrated.emplace(key,baseline.at(key));}DomainOperation op;op.target=TargetId(id_);op.type="decal.properties.replace.v1";op.payload=EditorValue::Object{{"values",std::move(migrated)}};auto result=applyDomainOperation(op);if(result.ok())clearDirtyRegion();return result;}
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
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Stable, serializable authoring document for one projected decal.
Definition DecalTarget.h:33
const EditorValue * value(const std::string &path) const
Read a renderer-neutral property by stable path.
Definition DecalTarget.cpp:42
eve::Result< eve::Revision > currentRevision(const SelectionSnapshot &selection) const override
Current revision.
Definition DecalTarget.cpp:34
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
Definition DecalTarget.cpp:45
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
Definition DecalTarget.cpp:68
PropertySchema schema(const SelectionSnapshot &selection) const override
Schema.
Definition DecalTarget.cpp:40
EditorValue snapshotValue() const
Capture schema-version-two decal content.
Definition DecalTarget.cpp:71
PropertyReadResult read(const SelectionSnapshot &selection, const PropertyPath &path) const override
Reads .
Definition DecalTarget.cpp:41
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
Definition DecalTarget.cpp:69
void * queryCapability(const CapabilityId &capability) override
Query an optional target capability.
Definition DecalTarget.cpp:32
Result< DomainOperation > makeSet(const SelectionSnapshot &selection, const PropertyPath &path, const EditorValue &value, PropertySetMode mode) const override
Make set.
Definition DecalTarget.cpp:43
Result< DomainOperation > makeReset(const SelectionSnapshot &selection, const PropertyPath &path) const override
Make reset.
Definition DecalTarget.cpp:44
Result< void > loadSnapshot(const EditorValue &snapshot)
Atomically load v4 content or migrate v1-v3 content with compatible projection defaults.
Definition DecalTarget.cpp:72
std::vector< EditorDiagnostic > validate() const
Validate projection geometry, fades, UVs and texture-channel rules.
Definition DecalTarget.cpp:70
void bumpRevision()
Advance the revision without touching the dirty region.
Definition EditableTarget.h:179
Revision revisionValue() const noexcept
Return the revision as the shared protocol revision type.
Definition EditableTarget.h:169
void widenDirty()
Mark an unknown area dirty without advancing the revision.
Definition EditableTarget.h:177
virtual void clearDirtyRegion()=0
Clears dirty region.
UI-independent property access for an immutable selection snapshot.
Definition EditingProperty.h:139
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
Definition EditingValue.h:19
editing::PropertySchema PropertySchema
Definition ArchSpaceTarget.h:36
editing::PropertyDescriptor PropertyDescriptor
Definition ArchSpaceTarget.h:31
editing::PropertyPath PropertyPath
Definition ArchSpaceTarget.h:33
Definition DecalGizmo.cpp:5
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
Definition EditingResult.h:25
const EditorValue * field(const EditorValue &value, const char *name)
Definition RoadNetworkEditTarget.cpp:15
@ InvalidArgument
@ PreconditionViolation
Definition Container.h:602
std::vector< std::string > affectedProperties
Definition EditingProtocol.h:52
PropertyDescriptorLookup find(const PropertyPath &path) const
Finds find.
Definition EditingProperty.cpp:9
Stable discovery metadata exposed by every editable target.
Definition EditableTarget.h:39