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_mesh.h>
17 
18 #include <meta/ext/concrete_base_object.h>
19 
20 #include "bind_templates.inl"
21 #include "intf_multi_mesh_initialization.h"
22 #include "node_impl.h"
23 #include "task_utils.h"
24 
25 using SCENE_NS::MakeTask;
26 namespace {
27 
28 class MultiMeshImpl : public META_NS::ObjectFwd<MultiMeshImpl, SCENE_NS::ClassId::MultiMeshProxy,
29                           META_NS::ClassId::Object, SCENE_NS::IMultiMeshProxy, IMultimeshInitilization> {
30     META_IMPLEMENT_INTERFACE_PROPERTY(
31         SCENE_NS::IMultiMeshProxy, SCENE_NS::IMaterial::Ptr, MaterialOverride, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
32     // META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(
33     //     SCENE_NS::IMultiMeshProxy, BASE_NS::string, MaterialOverrideUri, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
34     META_IMPLEMENT_INTERFACE_PROPERTY(
35         SCENE_NS::IMultiMeshProxy, SCENE_NS::IMesh::Ptr, Mesh, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
36     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMultiMeshProxy, size_t, VisibleInstanceCount, 0u)
37     META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMultiMeshProxy, BASE_NS::Math::Vec4, CustomData)
38     META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMultiMeshProxy, BASE_NS::Math::Mat4X4, Transforms)
39 
40     void SetInstanceCount(size_t count) override
41     {
42         // post to engine
43         if (auto sh = sceneHolder_.lock()) {
44             sh->QueueEngineTask(MakeTask(
__anonac8615180202(auto selfObject) 45                                     [count](auto selfObject) {
46                                         if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
47                                             if (auto sceneHolder = self->sceneHolder_.lock()) {
48                                                 CORE_NS::Entity mm;
49                                                 mm.id = self->handle_;
50                                                 sceneHolder->SetInstanceCountMultimeshArray(mm, count);
51                                             }
52                                         }
53                                         return false;
54                                     },
55                                     GetSelf()),
56                 false);
57         }
58 
59         // Make sure that array properties are in sync
60         auto size = META_ACCESS_PROPERTY(CustomData)->GetSize();
61         assert(size == META_ACCESS_PROPERTY(Transforms)->GetSize());
62         do {
63             if (count > size) {
64                 META_ACCESS_PROPERTY(CustomData)->AddValue({ 1.f, 1.f, 1.f, 1.f });
65                 META_ACCESS_PROPERTY(Transforms)->AddValue(BASE_NS::Math::IDENTITY_4X4);
66             } else if (count < size) {
67                 META_ACCESS_PROPERTY(CustomData)->RemoveAt(size - 1);
68                 META_ACCESS_PROPERTY(Transforms)->RemoveAt(size - 1);
69             }
70             size = META_ACCESS_PROPERTY(CustomData)->GetSize();
71         } while (size != count);
72     }
73 
74     SceneHolder::WeakPtr sceneHolder_;
75     uint64_t handle_ {};
76     BASE_NS::vector<CORE_NS::Entity> overridenMaterials_;
77 
Initialize(SceneHolder::Ptr sceneHolder,size_t instanceCount,CORE_NS::Entity baseComponent)78     void Initialize(SceneHolder::Ptr sceneHolder, size_t instanceCount, CORE_NS::Entity baseComponent) override
79     {
80         sceneHolder_ = sceneHolder;
81         if (auto sh = sceneHolder) {
82             sh->QueueEngineTask(MakeTask(
83                                     [baseComponent](auto sceneHolder, auto self) {
84                                         auto entity = sceneHolder->CreateMultiMeshInstance(baseComponent);
85                                         static_cast<MultiMeshImpl*>(self.get())->handle_ = entity.id;
86 
87                                         return false;
88                                     },
89                                     sceneHolder_, GetSelf()),
90                 false);
91         }
92         SetInstanceCount(instanceCount);
93     }
94 
Build(const IMetadata::Ptr & data)95     bool Build(const IMetadata::Ptr& data) override
96     {
97         // subscribe mesh changes
98         Mesh()->OnChanged()->AddHandler(
99             META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
100                 if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
101                     if (auto sh = self->sceneHolder_.lock()) {
102                         sh->QueueEngineTask(MakeTask([weak]() {
103                             if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
104                                 auto mesh = interface_pointer_cast<INodeEcsInterfacePrivate>(self->Mesh()->GetValue());
105                                 if (!mesh || !mesh->EcsObject()) {
106                                     return false; // Not sure if user should be able to reset ecs mesh by
107                                                   // setting the property as null
108                                 }
109                                 if (auto sceneHolder = self->sceneHolder_.lock()) {
110                                     CORE_NS::Entity mm;
111                                     mm.id = self->handle_;
112                                     sceneHolder->SetMeshMultimeshArray(mm, mesh->EcsObject()->GetEntity());
113                                 }
114                             }
115                             return false;
116                         }),
117                             false);
118                     }
119                 }
120             }),
121             reinterpret_cast<uint64_t>(this));
122 
123         // subscribe material changes
124         MaterialOverride()->OnChanged()->AddHandler(
125             META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
126                 if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
127                     if (auto sh = self->sceneHolder_.lock()) {
128                         sh->QueueEngineTask(
129                             MakeTask(
130                                 [](auto selfObject) {
131                                     if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
132                                         if (auto sceneHolder = self->sceneHolder_.lock()) {
133                                             CORE_NS::Entity mm;
134                                             mm.id = self->handle_;
135                                             auto material = interface_pointer_cast<INodeEcsInterfacePrivate>(
136                                                 self->MaterialOverride()->GetValue());
137                                             if (!material || !material->EcsObject()) {
138                                                 if (!self->overridenMaterials_.empty()) {
139                                                     sceneHolder->ResetOverrideMaterialMultimeshArray(
140                                                         mm, self->overridenMaterials_);
141                                                 }
142                                             } else {
143                                                 auto backup = sceneHolder->SetOverrideMaterialMultimeshArray(
144                                                     mm, material->EcsObject()->GetEntity());
145                                                 if (self->overridenMaterials_.empty()) {
146                                                     self->overridenMaterials_ =
147                                                         backup; // store backup only for the first change
148                                                 }
149                                             }
150                                         }
151                                     }
152                                     return false;
153                                 },
154                                 weak),
155                             false);
156                     }
157                 }
158             }),
159             reinterpret_cast<uint64_t>(this));
160 
161         // subscribe visible count changes
162         VisibleInstanceCount()->OnChanged()->AddHandler(
163             META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
164                 if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
165                     auto count = self->VisibleInstanceCount()->GetValue();
166                     if (auto sh = self->sceneHolder_.lock()) {
167                         sh->QueueEngineTask(MakeTask(
168                                                 [count](auto selfObject) {
169                                                     if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
170                                                         if (auto sceneHolder = self->sceneHolder_.lock()) {
171                                                             CORE_NS::Entity mm;
172                                                             mm.id = self->handle_;
173                                                             sceneHolder->SetVisibleCountMultimeshArray(mm, count);
174                                                         }
175                                                     }
176                                                     return false;
177                                                 },
178                                                 weak),
179                             false);
180                     }
181                 }
182             }),
183             reinterpret_cast<uint64_t>(this));
184 
185         //todo
186         // subscribe CustomData changes, write only
187         /*CustomData()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IMetaArrayProperty::
188                                                       OnChangedType>([weak = BASE_NS::weak_ptr(GetSelf())](
189                                                                          META::ArrayChangeNotification::ConstPtr ptr) {
190             if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
191                 for (auto& ref : ptr->Changes) {
192                     if (ref.Type == META::ArrayChangeNotification::MODIFIED ||
193                         ref.Type == META::ArrayChangeNotification::ADDED) {
194                         auto ix = ref.Begin;
195                         auto data = self->CustomData()->Get(ix);
196                         if (auto sh = self->sceneHolder_.lock()) {
197                             sh->QueueEngineTask(
198                                 MakeTask(
199                                     [data, ix](auto selfObject) {
200                                         if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
201                                             if (auto sceneHolder = self->sceneHolder_.lock()) {
202                                                 CORE_NS::Entity mm;
203                                                 mm.id = self->handle_;
204                                                 sceneHolder->SetCustomData(mm, ix, { data.x, data.y, data.z, data.w });
205                                             }
206                                         }
207                                         return false;
208                                     },
209                                     weak),
210                                 false);
211                         }
212                     }
213                 }
214             }
215         }),
216             reinterpret_cast<uint64_t>(this));*/
217 
218         //todo
219         // subscribe Transformation changes, write only
220         /*
221         Transforms()->OnChanged()->AddHandler(
222             META_NS::MakeCallback<META_NS::IMetaArrayProperty::OnChangedType>(
223                 [weak = BASE_NS::weak_ptr(GetSelf())](META::ArrayChangeNotification::ConstPtr ptr) {
224                     if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
225                         for (auto& ref : ptr->Changes) {
226                             if (ref.Type == META::ArrayChangeNotification::MODIFIED ||
227                                 ref.Type == META::ArrayChangeNotification::ADDED) {
228                                 auto ix = ref.Begin;
229                                 auto data = self->Transforms()->Get(ix);
230                                 if (auto sh = self->sceneHolder_.lock()) {
231                                     sh->QueueEngineTask(
232                                         MakeTask(
233                                             [data, ix](auto selfObject) {
234                                                 if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
235                                                     if (auto sceneHolder = self->sceneHolder_.lock()) {
236                                                         CORE_NS::Entity mm;
237                                                         mm.id = self->handle_;
238                                                         sceneHolder->SetTransformation(mm, ix, data);
239                                                     }
240                                                 }
241                                                 return false;
242                                             },
243                                             weak),
244                                         false);
245                                 }
246                             }
247                         }
248                     }
249                 }),
250             reinterpret_cast<uint64_t>(this));
251         */
252         return true;
253     }
254 };
255 } // namespace
SCENE_BEGIN_NAMESPACE()256 SCENE_BEGIN_NAMESPACE()
257 void RegisterMultiMeshImpl()
258 {
259     META_NS::GetObjectRegistry().RegisterObjectType<MultiMeshImpl>();
260 }
UnregisterMultiMeshImpl()261 void UnregisterMultiMeshImpl()
262 {
263     META_NS::GetObjectRegistry().UnregisterObjectType<MultiMeshImpl>();
264 }
265 
266 SCENE_END_NAMESPACE()