• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "material.h"
17 
18 #include <scene/ext/util.h>
19 
20 #include <core/log.h>
21 
22 #include <meta/api/engine/util.h>
23 #include <meta/api/make_callback.h>
24 
25 #include "../entity_converting_value.h"
26 #include "meta/interface/engine/intf_engine_value_manager.h"
27 #include "texture.h"
28 
29 SCENE_BEGIN_NAMESPACE()
30 namespace {
31 struct ShaderConverter {
ShaderConverter__anon835064240111::ShaderConverter32     ShaderConverter(const IInternalScene::Ptr& scene, META_NS::Property<CORE3D_NS::MaterialComponent::Shader> p)
33         : scene_(scene), p_(p)
34     {}
35 
36     using SourceType = IShader::Ptr;
37     using TargetType = CORE3D_NS::MaterialComponent::Shader;
38 
ConvertToSource__anon835064240111::ShaderConverter39     SourceType ConvertToSource(META_NS::IAny& any, const TargetType& v) const
40     {
41         auto p = META_NS::GetPointer<IShader>(any);
42         if (auto scene = scene_.lock()) {
43             scene
44                 ->AddTask([&] {
45                     if (!p) {
46                         p = interface_pointer_cast<IShader>(scene->CreateObject(ClassId::Shader));
47                     }
48                     if (auto i = interface_cast<IShaderState>(p)) {
49                         if (auto rhman = static_cast<CORE3D_NS::IRenderHandleComponentManager*>(
50                                 scene->GetEcsContext().FindComponent<CORE3D_NS::RenderHandleComponent>())) {
51                             i->SetShaderState(scene, rhman->GetRenderHandleReference(v.shader), v.shader,
52                                 rhman->GetRenderHandleReference(v.graphicsState), v.graphicsState);
53 
54                             if (auto ig = interface_cast<IGraphicsState>(p)) {
55                                 auto s = ig->GetGraphicsState();
56                                 if (s != v.graphicsState) {
57                                     auto copy = v;
58                                     copy.graphicsState = s;
59 
60                                     p_.GetUnlockedAccess().SetValue(copy);
61                                 }
62                             }
63                         }
64                     }
65                 })
66                 .Wait();
67         }
68         return p;
69     }
ConvertToTarget__anon835064240111::ShaderConverter70     TargetType ConvertToTarget(const SourceType& v) const
71     {
72         TargetType res;
73         if (auto scene = scene_.lock()) {
74             if (auto i = interface_cast<IEcsResource>(v)) {
75                 res.shader = scene->GetEcsContext().GetEntityReference(i->GetEntity());
76             }
77             if (auto i = interface_cast<IGraphicsState>(v)) {
78                 res.graphicsState = i->GetGraphicsState();
79             }
80         }
81         return res;
82     }
83 
84 private:
85     IInternalScene::WeakPtr scene_;
86     META_NS::Property<CORE3D_NS::MaterialComponent::Shader> p_;
87 };
88 struct RenderSortConverter {
89     using SourceType = SCENE_NS::RenderSort;
90     using TargetType = CORE3D_NS::MaterialComponent::RenderSort;
91 
ConvertToSource__anon835064240111::RenderSortConverter92     SourceType ConvertToSource(META_NS::IAny&, const TargetType& v) const
93     {
94         return SourceType { v.renderSortLayer, v.renderSortLayerOrder };
95     }
ConvertToTarget__anon835064240111::RenderSortConverter96     TargetType ConvertToTarget(const SourceType& v) const
97     {
98         return TargetType { v.renderSortLayer, v.renderSortLayerOrder };
99     }
100 };
101 struct LightingFlagsConverter {
102     using SourceType = SCENE_NS::LightingFlags;
103     using TargetType = uint32_t;
104 
ConvertToSource__anon835064240111::LightingFlagsConverter105     SourceType ConvertToSource(META_NS::IAny&, const TargetType& v) const
106     {
107         return static_cast<SourceType>(v);
108     }
ConvertToTarget__anon835064240111::LightingFlagsConverter109     TargetType ConvertToTarget(const SourceType& v) const
110     {
111         return static_cast<TargetType>(v);
112     }
113 };
114 } // namespace
115 
CreateEntity(const IInternalScene::Ptr & scene)116 CORE_NS::Entity Material::CreateEntity(const IInternalScene::Ptr& scene)
117 {
118     const auto& ecs = scene->GetEcsContext().GetNativeEcs();
119     const auto materialManager = CORE_NS::GetManager<CORE3D_NS::IMaterialComponentManager>(*ecs);
120     if (!materialManager) {
121         return {};
122     }
123     auto ent = ecs->GetEntityManager().Create();
124     materialManager->Create(ent);
125     return ent;
126 }
127 
SetEcsObject(const IEcsObject::Ptr & obj)128 bool Material::SetEcsObject(const IEcsObject::Ptr& obj)
129 {
130     if (Super::SetEcsObject(obj)) {
131         if (auto att = GetSelf<META_NS::IAttach>()) {
132             if (auto attc = att->GetAttachmentContainer(false)) {
133                 if (auto c = attc->FindByName<IInternalMaterial>("MaterialComponent")) {
134                     material_ = c;
135                 }
136             }
137         }
138         if (!material_) {
139             auto p = META_NS::GetObjectRegistry().Create<IInternalMaterial>(ClassId::MaterialComponent);
140             if (auto acc = interface_cast<IEcsObjectAccess>(p)) {
141                 if (acc->SetEcsObject(obj)) {
142                     material_ = p;
143                 }
144             }
145         }
146     }
147     return material_ != nullptr;
148 }
149 
InitDynamicProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)150 bool Material::InitDynamicProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
151 {
152     BASE_NS::string name = p->GetName();
153     if (name == "MaterialShader" || name == "DepthShader") {
154         auto ep = object_->CreateEngineProperty(path).GetResult();
155         auto i = interface_cast<META_NS::IStackProperty>(p);
156         return ep && i &&
157                i->PushValue(
158                    META_NS::IValue::Ptr(new ConvertingValue<ShaderConverter>(ep, { object_->GetScene(), ep })));
159     }
160     if (name == "Textures") {
161         return ConstructTextures(p);
162     }
163     if (name == "RenderSort") {
164         auto ep = material_->RenderSort();
165         auto i = interface_cast<META_NS::IStackProperty>(p);
166         return ep && i && i->PushValue(META_NS::IValue::Ptr(new ConvertingValue<RenderSortConverter>(ep)));
167     }
168     if (name == "LightingFlags") {
169         auto ep = material_->LightingFlags();
170         auto i = interface_cast<META_NS::IStackProperty>(p);
171         return ep && i && i->PushValue(META_NS::IValue::Ptr(new ConvertingValue<LightingFlagsConverter>(ep)));
172     }
173     return false;
174 }
175 
176 // clang-format off
177 const char* const TEXTURE_NAMES[] = {
178     "BASE_COLOR",
179     "NORMAL",
180     "MATERIAL",
181     "EMISSIVE",
182     "AO",
183     "CLEARCOAT",
184     "CLEARCOAT_ROUGHNESS",
185     "CLEARCOAT_NORMAL",
186     "SHEEN",
187     "TRANSMISSION",
188     "SPECULAR"
189 };
190 constexpr size_t TEXTURE_NAMES_SIZE = sizeof(TEXTURE_NAMES) / sizeof(*TEXTURE_NAMES);
191 // clang-format on
192 
ConstructTextures(const META_NS::IProperty::Ptr & p)193 bool Material::ConstructTextures(const META_NS::IProperty::Ptr& p)
194 {
195     auto& r = META_NS::GetObjectRegistry();
196     BASE_NS::vector<ITexture::Ptr> texs;
197     auto mtex = material_->Textures()->GetValue();
198     auto mdata = r.Create<META_NS::IMetadata>(META_NS::ClassId::Object);
199     auto index = META_NS::ConstructProperty<size_t>("Index");
200     mdata->AddProperty(index);
201     for (size_t i = 0; i != mtex.size(); ++i) {
202         index->SetValue(i);
203         auto t = r.Create<ITexture>(ClassId::Texture, mdata);
204         if (auto access = interface_cast<IEcsObjectAccess>(t)) {
205             access->SetEcsObject(GetEcsObject());
206             if (auto named = interface_cast<META_NS::INamed>(t); named && i < TEXTURE_NAMES_SIZE) {
207                 named->Name()->SetValue(TEXTURE_NAMES[i]);
208             }
209             texs.push_back(t);
210         } else {
211             CORE_LOG_E("Failed to create texture for material");
212             return false;
213         }
214     }
215     META_NS::ArrayProperty<ITexture::Ptr> prop { p };
216     if (prop) {
217         prop->SetValue(texs);
218     }
219     return static_cast<bool>(prop);
220 }
221 
GetCustomProperties() const222 META_NS::IMetadata::Ptr Material::GetCustomProperties() const
223 {
224     META_NS::IMetadata::Ptr customs;
225     if (const auto obj = GetEcsObject()) {
226         BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
227         if (SyncCustomProperties(&values)) {
228             customs = META_NS::GetObjectRegistry().Create<META_NS::IMetadata>(META_NS::ClassId::Object);
229             for (auto&& v : values) {
230                 BASE_NS::string pname(SCENE_NS::PropertyName(v->GetName()));
231                 if (auto prop = customs->GetProperty(pname)) {
232                     SetEngineValueToProperty(prop, v);
233                 } else {
234                     customs->AddProperty(META_NS::PropertyFromEngineValue(pname, v));
235                 }
236             }
237         }
238     }
239     return customs;
240 }
241 
GetCustomProperty(BASE_NS::string_view name) const242 META_NS::IProperty::Ptr Material::GetCustomProperty(BASE_NS::string_view name) const
243 {
244     const auto obj = GetEcsObject();
245     if (!obj) {
246         return nullptr;
247     }
248     const auto manager = obj->GetEngineValueManager();
249     if (!manager) {
250         return nullptr;
251     }
252 
253     if (!SyncCustomProperties({})) {
254         CORE_LOG_W("Syncing properties to engine values failed. Using old values if available.");
255     }
256     BASE_NS::string fullName { name };
257     if (!name.starts_with("MaterialComponent.customProperties.")) {
258         fullName = "MaterialComponent.customProperties." + fullName;
259     }
260     return META_NS::PropertyFromEngineValue(fullName, manager->GetEngineValue(fullName));
261 }
262 
SyncCustomProperties(BASE_NS::vector<META_NS::IEngineValue::Ptr> * synced_values) const263 bool Material::SyncCustomProperties(BASE_NS::vector<META_NS::IEngineValue::Ptr>* synced_values) const
264 {
265     const auto obj = GetEcsObject();
266     if (!material_ || !obj) {
267         return false;
268     }
269     const auto manager = obj->GetEngineValueManager();
270     const auto allCustomProps = META_NS::GetEngineValueFromProperty(material_->CustomProperties());
271     if (!manager || !allCustomProps) {
272         return false;
273     }
274 
275     auto doSync = [&]() -> bool {
276         // syncing material shader updates the custom properties
277         obj->GetScene()->SyncProperty(MaterialShader(), META_NS::EngineSyncDirection::AUTO);
278         obj->GetScene()->SyncProperty(material_->CustomProperties(), META_NS::EngineSyncDirection::FROM_ENGINE);
279         return manager->ConstructValues(allCustomProps, { "", synced_values });
280     };
281     return obj->GetScene()->AddTask(doSync).Wait();
282 }
283 
284 SCENE_END_NAMESPACE()
285