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 #include <scene_plugin/api/mesh_uid.h>
16 #include <scene_plugin/interface/intf_material.h>
17 
18 #include <meta/ext/concrete_base_object.h>
19 
20 #include "bind_templates.inl"
21 #include "intf_submesh_bridge.h"
22 #include "node_impl.h"
23 #include "submesh_handler_uid.h"
24 #include "task_utils.h"
25 
26 using SCENE_NS::MakeTask;
27 
28 namespace {
29 class SubMeshImpl : public META_NS::ObjectFwd<SubMeshImpl, SCENE_NS::ClassId::SubMesh, META_NS::ClassId::Object,
30                         SCENE_NS::ISubMesh, SCENE_NS::ISubMeshPrivate> {
31     META_IMPLEMENT_INTERFACE_PROPERTY(META_NS::INamed, BASE_NS::string, Name, {})
32     META_IMPLEMENT_INTERFACE_PROPERTY(
33         SCENE_NS::ISubMesh, SCENE_NS::IMaterial::Ptr, Material, {})
34     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ISubMesh, uint64_t, Handle, {}, META_NS::ObjectFlagBits::INTERNAL)
35     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ISubMesh, BASE_NS::Math::Vec3, AABBMin,
36         BASE_NS::Math::Vec3(0.f, 0.f, 0.f), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
37     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ISubMesh, BASE_NS::Math::Vec3, AABBMax,
38         BASE_NS::Math::Vec3(0.f, 0.f, 0.f), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
39     META_IMPLEMENT_INTERFACE_PROPERTY(
40         SCENE_NS::ISubMesh, uint8_t, RenderSortLayerOrder, 0u, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
41     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::ISubMesh, BASE_NS::string, MaterialUri, "",
42         META_NS::DEFAULT_PROPERTY_FLAGS | META_NS::ObjectFlagBits::INTERNAL)
43 
44 public:
Build(const META_NS::IMetadata::Ptr & data)45     bool Build(const META_NS::IMetadata::Ptr& data) override
46     {
47         // subscribe to material changes.
48         Material()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
49             // Material has changed.
50             auto material = Material()->GetValue();
51 
52             // If this change was not triggered by us, we will store the value.
53             if (!isSettingDefaults_) {
54                 SaveCurrentMaterial(material);
55             }
56 
57             // Override material always overrides everything.
58             // This could use validator as well, but MetaObject Validate() function was not invoked properly.
59             if (overrideMaterial_) {
60                 material = overrideMaterial_;
61             } else if (!material) {
62                 // No material / case reset.
63                 material = defaultMaterial_;
64             }
65 
66             UpdateMaterialToScene(material);
67         }));
68 
69         return true;
70     }
71 
SetRenderSortLayerOrder(uint8_t order)72     void SetRenderSortLayerOrder(uint8_t order) override
73     {
74         for (auto& ite : submeshHandlers_) {
75             if (auto bridge = ite.lock()) {
76                 bridge->SetRenderSortLayerOrder(META_NS::GetValue(Handle()), order);
77             }
78         }
79     }
80 
SetAABBMin(BASE_NS::Math::Vec3 vec)81     void SetAABBMin(BASE_NS::Math::Vec3 vec) override
82     {
83         for (auto& ite : submeshHandlers_) {
84             if (auto bridge = ite.lock()) {
85                 bridge->SetAABBMin(META_NS::GetValue(Handle()), vec);
86             }
87         }
88     }
89 
SetAABBMax(BASE_NS::Math::Vec3 vec)90     void SetAABBMax(BASE_NS::Math::Vec3 vec) override
91     {
92         for (auto& ite : submeshHandlers_) {
93             if (auto bridge = ite.lock()) {
94                 bridge->SetAABBMax(META_NS::GetValue(Handle()), vec);
95             }
96         }
97     }
98 
SetMaterial(SCENE_NS::IMaterial::Ptr material)99     void SetMaterial(SCENE_NS::IMaterial::Ptr material) override
100     {
101         Material()->SetValue(material);
102     }
103 
UpdateMaterialToScene(SCENE_NS::IMaterial::Ptr material)104     void UpdateMaterialToScene(SCENE_NS::IMaterial::Ptr material)
105     {
106         // Activate material to scene.
107         for (auto& ite : submeshHandlers_) {
108             if (auto bridge = ite.lock()) {
109                 bridge->SetMaterialToEcs(META_NS::GetValue(Handle()), material);
110             }
111         }
112     }
113 
114 public: // ISubMeshPrivate
AddSubmeshBrigde(SCENE_NS::ISubMeshBridge::Ptr bridge)115     void AddSubmeshBrigde(SCENE_NS::ISubMeshBridge::Ptr bridge) override
116     {
117         for (auto& existingBridge : submeshHandlers_) {
118             if (bridge == existingBridge.lock()) {
119                 return;
120             }
121         }
122 
123         submeshHandlers_.push_back(bridge);
124 
125         // Store initial material that we have assigned right now.
126         currentMaterial_ = GetValue(Material());
127         if (currentMaterial_) {
128             bridge->SetMaterialToEcs(META_NS::GetValue(Handle()), currentMaterial_);
129         }
130     }
131 
RemoveSubmeshBrigde(SCENE_NS::ISubMeshBridge::Ptr bridge)132     virtual void RemoveSubmeshBrigde(SCENE_NS::ISubMeshBridge::Ptr bridge) override
133     {
134         for (auto ite = submeshHandlers_.cbegin(); ite != submeshHandlers_.cend();) {
135             auto strong = ite->lock();
136             if (!strong || bridge == strong) {
137                 ite = submeshHandlers_.erase(ite);
138             } else {
139                 ite++;
140             }
141         }
142     }
143 
GetEntity() const144     CORE_NS::Entity GetEntity() const override
145     {
146         if (!submeshHandlers_.empty()) {
147             if (auto first = submeshHandlers_.begin()->lock()) {
148                 return first->GetEntity();
149             }
150         }
151 
152         return {};
153     }
154 
RestoreDefaultMaterial()155     void RestoreDefaultMaterial() override
156     {
157         Material()->SetValue(defaultMaterial_);
158     }
159 
SetDefaultMaterial(SCENE_NS::IMaterial::Ptr material)160     void SetDefaultMaterial(SCENE_NS::IMaterial::Ptr material) override
161     {
162         isSettingDefaults_ = true;
163 
164         if (!defaultMaterialIsSet_) {
165             // Store default material.
166             defaultMaterial_ = material;
167             defaultMaterialIsSet_ = true;
168 
169             // also make it default to this property, so that Reset() will work.
170             // Currently this causes material (and its changes) not to be serialized to .ui
171             // auto* directAccess =
172             // interface_cast<META_NS::IPropertyDirectAccess<SCENE_NS::IMaterial::Ptr>>(Material()); if (directAccess) {
173             //}
174 
175             // Activate default material if there is no current material.
176             if (!META_NS::GetValue(Material())) {
177                 Material()->SetValue(material);
178             }
179         }
180 
181         isSettingDefaults_ = false;
182     }
183 
SetOverrideMaterial(SCENE_NS::IMaterial::Ptr material)184     void SetOverrideMaterial(SCENE_NS::IMaterial::Ptr material) override
185     {
186         isSettingDefaults_ = true;
187 
188         // Store override material.
189         overrideMaterial_ = material;
190 
191         // If override material, make it active.
192         if (overrideMaterial_) {
193             UpdateMaterialToScene(overrideMaterial_);
194         } else {
195             // Otherwise restore the current material / default material.
196             UpdateMaterialToScene(currentMaterial_ ? currentMaterial_ : defaultMaterial_);
197         }
198         isSettingDefaults_ = false;
199     }
200 
SaveCurrentMaterial(SCENE_NS::IMaterial::Ptr material)201     void SaveCurrentMaterial(SCENE_NS::IMaterial::Ptr material)
202     {
203         // This material also becomes the "current" value.
204         currentMaterial_ = material;
205 
206         if (!currentMaterial_) {
207             Material()->SetValue(defaultMaterial_);
208         }
209     }
210 
211     bool defaultMaterialIsSet_ { false };
212     SCENE_NS::IMaterial::Ptr defaultMaterial_;
213     SCENE_NS::IMaterial::Ptr currentMaterial_;
214     SCENE_NS::IMaterial::Ptr overrideMaterial_;
215 
216     bool isSettingDefaults_ { false };
217     BASE_NS::vector<SCENE_NS::ISubMeshBridge::WeakPtr> submeshHandlers_;
218 };
219 } // namespace
SCENE_BEGIN_NAMESPACE()220 SCENE_BEGIN_NAMESPACE()
221 
222 void RegisterSubMeshImpl()
223 {
224     META_NS::GetObjectRegistry().RegisterObjectType<SubMeshImpl>();
225 }
UnregisterSubMeshImpl()226 void UnregisterSubMeshImpl()
227 {
228     META_NS::GetObjectRegistry().UnregisterObjectType<SubMeshImpl>();
229 }
230 SCENE_END_NAMESPACE()
231