18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci#include <scene_plugin/api/mesh_uid.h>
168bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_mesh.h>
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/ext/concrete_base_object.h>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ci#include "bind_templates.inl"
218bf80f4bSopenharmony_ci#include "intf_multi_mesh_initialization.h"
228bf80f4bSopenharmony_ci#include "node_impl.h"
238bf80f4bSopenharmony_ci#include "task_utils.h"
248bf80f4bSopenharmony_ci
258bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask;
268bf80f4bSopenharmony_cinamespace {
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ciclass MultiMeshImpl : public META_NS::ObjectFwd<MultiMeshImpl, SCENE_NS::ClassId::MultiMeshProxy,
298bf80f4bSopenharmony_ci                          META_NS::ClassId::Object, SCENE_NS::IMultiMeshProxy, IMultimeshInitilization> {
308bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(
318bf80f4bSopenharmony_ci        SCENE_NS::IMultiMeshProxy, SCENE_NS::IMaterial::Ptr, MaterialOverride, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
328bf80f4bSopenharmony_ci    // META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(
338bf80f4bSopenharmony_ci    //     SCENE_NS::IMultiMeshProxy, BASE_NS::string, MaterialOverrideUri, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
348bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(
358bf80f4bSopenharmony_ci        SCENE_NS::IMultiMeshProxy, SCENE_NS::IMesh::Ptr, Mesh, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
368bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMultiMeshProxy, size_t, VisibleInstanceCount, 0u)
378bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMultiMeshProxy, BASE_NS::Math::Vec4, CustomData)
388bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMultiMeshProxy, BASE_NS::Math::Mat4X4, Transforms)
398bf80f4bSopenharmony_ci
408bf80f4bSopenharmony_ci    void SetInstanceCount(size_t count) override
418bf80f4bSopenharmony_ci    {
428bf80f4bSopenharmony_ci        // post to engine
438bf80f4bSopenharmony_ci        if (auto sh = sceneHolder_.lock()) {
448bf80f4bSopenharmony_ci            sh->QueueEngineTask(MakeTask(
458bf80f4bSopenharmony_ci                                    [count](auto selfObject) {
468bf80f4bSopenharmony_ci                                        if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
478bf80f4bSopenharmony_ci                                            if (auto sceneHolder = self->sceneHolder_.lock()) {
488bf80f4bSopenharmony_ci                                                CORE_NS::Entity mm;
498bf80f4bSopenharmony_ci                                                mm.id = self->handle_;
508bf80f4bSopenharmony_ci                                                sceneHolder->SetInstanceCountMultimeshArray(mm, count);
518bf80f4bSopenharmony_ci                                            }
528bf80f4bSopenharmony_ci                                        }
538bf80f4bSopenharmony_ci                                        return false;
548bf80f4bSopenharmony_ci                                    },
558bf80f4bSopenharmony_ci                                    GetSelf()),
568bf80f4bSopenharmony_ci                false);
578bf80f4bSopenharmony_ci        }
588bf80f4bSopenharmony_ci
598bf80f4bSopenharmony_ci        // Make sure that array properties are in sync
608bf80f4bSopenharmony_ci        auto size = META_ACCESS_PROPERTY(CustomData)->GetSize();
618bf80f4bSopenharmony_ci        assert(size == META_ACCESS_PROPERTY(Transforms)->GetSize());
628bf80f4bSopenharmony_ci        do {
638bf80f4bSopenharmony_ci            if (count > size) {
648bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(CustomData)->AddValue({ 1.f, 1.f, 1.f, 1.f });
658bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(Transforms)->AddValue(BASE_NS::Math::IDENTITY_4X4);
668bf80f4bSopenharmony_ci            } else if (count < size) {
678bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(CustomData)->RemoveAt(size - 1);
688bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(Transforms)->RemoveAt(size - 1);
698bf80f4bSopenharmony_ci            }
708bf80f4bSopenharmony_ci            size = META_ACCESS_PROPERTY(CustomData)->GetSize();
718bf80f4bSopenharmony_ci        } while (size != count);
728bf80f4bSopenharmony_ci    }
738bf80f4bSopenharmony_ci
748bf80f4bSopenharmony_ci    SceneHolder::WeakPtr sceneHolder_;
758bf80f4bSopenharmony_ci    uint64_t handle_ {};
768bf80f4bSopenharmony_ci    BASE_NS::vector<CORE_NS::Entity> overridenMaterials_;
778bf80f4bSopenharmony_ci
788bf80f4bSopenharmony_ci    void Initialize(SceneHolder::Ptr sceneHolder, size_t instanceCount, CORE_NS::Entity baseComponent) override
798bf80f4bSopenharmony_ci    {
808bf80f4bSopenharmony_ci        sceneHolder_ = sceneHolder;
818bf80f4bSopenharmony_ci        if (auto sh = sceneHolder) {
828bf80f4bSopenharmony_ci            sh->QueueEngineTask(MakeTask(
838bf80f4bSopenharmony_ci                                    [baseComponent](auto sceneHolder, auto self) {
848bf80f4bSopenharmony_ci                                        auto entity = sceneHolder->CreateMultiMeshInstance(baseComponent);
858bf80f4bSopenharmony_ci                                        static_cast<MultiMeshImpl*>(self.get())->handle_ = entity.id;
868bf80f4bSopenharmony_ci
878bf80f4bSopenharmony_ci                                        return false;
888bf80f4bSopenharmony_ci                                    },
898bf80f4bSopenharmony_ci                                    sceneHolder_, GetSelf()),
908bf80f4bSopenharmony_ci                false);
918bf80f4bSopenharmony_ci        }
928bf80f4bSopenharmony_ci        SetInstanceCount(instanceCount);
938bf80f4bSopenharmony_ci    }
948bf80f4bSopenharmony_ci
958bf80f4bSopenharmony_ci    bool Build(const IMetadata::Ptr& data) override
968bf80f4bSopenharmony_ci    {
978bf80f4bSopenharmony_ci        // subscribe mesh changes
988bf80f4bSopenharmony_ci        Mesh()->OnChanged()->AddHandler(
998bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
1008bf80f4bSopenharmony_ci                if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
1018bf80f4bSopenharmony_ci                    if (auto sh = self->sceneHolder_.lock()) {
1028bf80f4bSopenharmony_ci                        sh->QueueEngineTask(MakeTask([weak]() {
1038bf80f4bSopenharmony_ci                            if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
1048bf80f4bSopenharmony_ci                                auto mesh = interface_pointer_cast<INodeEcsInterfacePrivate>(self->Mesh()->GetValue());
1058bf80f4bSopenharmony_ci                                if (!mesh || !mesh->EcsObject()) {
1068bf80f4bSopenharmony_ci                                    return false; // Not sure if user should be able to reset ecs mesh by
1078bf80f4bSopenharmony_ci                                                  // setting the property as null
1088bf80f4bSopenharmony_ci                                }
1098bf80f4bSopenharmony_ci                                if (auto sceneHolder = self->sceneHolder_.lock()) {
1108bf80f4bSopenharmony_ci                                    CORE_NS::Entity mm;
1118bf80f4bSopenharmony_ci                                    mm.id = self->handle_;
1128bf80f4bSopenharmony_ci                                    sceneHolder->SetMeshMultimeshArray(mm, mesh->EcsObject()->GetEntity());
1138bf80f4bSopenharmony_ci                                }
1148bf80f4bSopenharmony_ci                            }
1158bf80f4bSopenharmony_ci                            return false;
1168bf80f4bSopenharmony_ci                        }),
1178bf80f4bSopenharmony_ci                            false);
1188bf80f4bSopenharmony_ci                    }
1198bf80f4bSopenharmony_ci                }
1208bf80f4bSopenharmony_ci            }),
1218bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));
1228bf80f4bSopenharmony_ci
1238bf80f4bSopenharmony_ci        // subscribe material changes
1248bf80f4bSopenharmony_ci        MaterialOverride()->OnChanged()->AddHandler(
1258bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
1268bf80f4bSopenharmony_ci                if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
1278bf80f4bSopenharmony_ci                    if (auto sh = self->sceneHolder_.lock()) {
1288bf80f4bSopenharmony_ci                        sh->QueueEngineTask(
1298bf80f4bSopenharmony_ci                            MakeTask(
1308bf80f4bSopenharmony_ci                                [](auto selfObject) {
1318bf80f4bSopenharmony_ci                                    if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
1328bf80f4bSopenharmony_ci                                        if (auto sceneHolder = self->sceneHolder_.lock()) {
1338bf80f4bSopenharmony_ci                                            CORE_NS::Entity mm;
1348bf80f4bSopenharmony_ci                                            mm.id = self->handle_;
1358bf80f4bSopenharmony_ci                                            auto material = interface_pointer_cast<INodeEcsInterfacePrivate>(
1368bf80f4bSopenharmony_ci                                                self->MaterialOverride()->GetValue());
1378bf80f4bSopenharmony_ci                                            if (!material || !material->EcsObject()) {
1388bf80f4bSopenharmony_ci                                                if (!self->overridenMaterials_.empty()) {
1398bf80f4bSopenharmony_ci                                                    sceneHolder->ResetOverrideMaterialMultimeshArray(
1408bf80f4bSopenharmony_ci                                                        mm, self->overridenMaterials_);
1418bf80f4bSopenharmony_ci                                                }
1428bf80f4bSopenharmony_ci                                            } else {
1438bf80f4bSopenharmony_ci                                                auto backup = sceneHolder->SetOverrideMaterialMultimeshArray(
1448bf80f4bSopenharmony_ci                                                    mm, material->EcsObject()->GetEntity());
1458bf80f4bSopenharmony_ci                                                if (self->overridenMaterials_.empty()) {
1468bf80f4bSopenharmony_ci                                                    self->overridenMaterials_ =
1478bf80f4bSopenharmony_ci                                                        backup; // store backup only for the first change
1488bf80f4bSopenharmony_ci                                                }
1498bf80f4bSopenharmony_ci                                            }
1508bf80f4bSopenharmony_ci                                        }
1518bf80f4bSopenharmony_ci                                    }
1528bf80f4bSopenharmony_ci                                    return false;
1538bf80f4bSopenharmony_ci                                },
1548bf80f4bSopenharmony_ci                                weak),
1558bf80f4bSopenharmony_ci                            false);
1568bf80f4bSopenharmony_ci                    }
1578bf80f4bSopenharmony_ci                }
1588bf80f4bSopenharmony_ci            }),
1598bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));
1608bf80f4bSopenharmony_ci
1618bf80f4bSopenharmony_ci        // subscribe visible count changes
1628bf80f4bSopenharmony_ci        VisibleInstanceCount()->OnChanged()->AddHandler(
1638bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() {
1648bf80f4bSopenharmony_ci                if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
1658bf80f4bSopenharmony_ci                    auto count = self->VisibleInstanceCount()->GetValue();
1668bf80f4bSopenharmony_ci                    if (auto sh = self->sceneHolder_.lock()) {
1678bf80f4bSopenharmony_ci                        sh->QueueEngineTask(MakeTask(
1688bf80f4bSopenharmony_ci                                                [count](auto selfObject) {
1698bf80f4bSopenharmony_ci                                                    if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
1708bf80f4bSopenharmony_ci                                                        if (auto sceneHolder = self->sceneHolder_.lock()) {
1718bf80f4bSopenharmony_ci                                                            CORE_NS::Entity mm;
1728bf80f4bSopenharmony_ci                                                            mm.id = self->handle_;
1738bf80f4bSopenharmony_ci                                                            sceneHolder->SetVisibleCountMultimeshArray(mm, count);
1748bf80f4bSopenharmony_ci                                                        }
1758bf80f4bSopenharmony_ci                                                    }
1768bf80f4bSopenharmony_ci                                                    return false;
1778bf80f4bSopenharmony_ci                                                },
1788bf80f4bSopenharmony_ci                                                weak),
1798bf80f4bSopenharmony_ci                            false);
1808bf80f4bSopenharmony_ci                    }
1818bf80f4bSopenharmony_ci                }
1828bf80f4bSopenharmony_ci            }),
1838bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));
1848bf80f4bSopenharmony_ci
1858bf80f4bSopenharmony_ci        //todo
1868bf80f4bSopenharmony_ci        // subscribe CustomData changes, write only
1878bf80f4bSopenharmony_ci        /*CustomData()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IMetaArrayProperty::
1888bf80f4bSopenharmony_ci                                                      OnChangedType>([weak = BASE_NS::weak_ptr(GetSelf())](
1898bf80f4bSopenharmony_ci                                                                         META::ArrayChangeNotification::ConstPtr ptr) {
1908bf80f4bSopenharmony_ci            if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
1918bf80f4bSopenharmony_ci                for (auto& ref : ptr->Changes) {
1928bf80f4bSopenharmony_ci                    if (ref.Type == META::ArrayChangeNotification::MODIFIED ||
1938bf80f4bSopenharmony_ci                        ref.Type == META::ArrayChangeNotification::ADDED) {
1948bf80f4bSopenharmony_ci                        auto ix = ref.Begin;
1958bf80f4bSopenharmony_ci                        auto data = self->CustomData()->Get(ix);
1968bf80f4bSopenharmony_ci                        if (auto sh = self->sceneHolder_.lock()) {
1978bf80f4bSopenharmony_ci                            sh->QueueEngineTask(
1988bf80f4bSopenharmony_ci                                MakeTask(
1998bf80f4bSopenharmony_ci                                    [data, ix](auto selfObject) {
2008bf80f4bSopenharmony_ci                                        if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
2018bf80f4bSopenharmony_ci                                            if (auto sceneHolder = self->sceneHolder_.lock()) {
2028bf80f4bSopenharmony_ci                                                CORE_NS::Entity mm;
2038bf80f4bSopenharmony_ci                                                mm.id = self->handle_;
2048bf80f4bSopenharmony_ci                                                sceneHolder->SetCustomData(mm, ix, { data.x, data.y, data.z, data.w });
2058bf80f4bSopenharmony_ci                                            }
2068bf80f4bSopenharmony_ci                                        }
2078bf80f4bSopenharmony_ci                                        return false;
2088bf80f4bSopenharmony_ci                                    },
2098bf80f4bSopenharmony_ci                                    weak),
2108bf80f4bSopenharmony_ci                                false);
2118bf80f4bSopenharmony_ci                        }
2128bf80f4bSopenharmony_ci                    }
2138bf80f4bSopenharmony_ci                }
2148bf80f4bSopenharmony_ci            }
2158bf80f4bSopenharmony_ci        }),
2168bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));*/
2178bf80f4bSopenharmony_ci
2188bf80f4bSopenharmony_ci        //todo
2198bf80f4bSopenharmony_ci        // subscribe Transformation changes, write only
2208bf80f4bSopenharmony_ci        /*
2218bf80f4bSopenharmony_ci        Transforms()->OnChanged()->AddHandler(
2228bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::IMetaArrayProperty::OnChangedType>(
2238bf80f4bSopenharmony_ci                [weak = BASE_NS::weak_ptr(GetSelf())](META::ArrayChangeNotification::ConstPtr ptr) {
2248bf80f4bSopenharmony_ci                    if (auto self = static_pointer_cast<MultiMeshImpl>(weak.lock())) {
2258bf80f4bSopenharmony_ci                        for (auto& ref : ptr->Changes) {
2268bf80f4bSopenharmony_ci                            if (ref.Type == META::ArrayChangeNotification::MODIFIED ||
2278bf80f4bSopenharmony_ci                                ref.Type == META::ArrayChangeNotification::ADDED) {
2288bf80f4bSopenharmony_ci                                auto ix = ref.Begin;
2298bf80f4bSopenharmony_ci                                auto data = self->Transforms()->Get(ix);
2308bf80f4bSopenharmony_ci                                if (auto sh = self->sceneHolder_.lock()) {
2318bf80f4bSopenharmony_ci                                    sh->QueueEngineTask(
2328bf80f4bSopenharmony_ci                                        MakeTask(
2338bf80f4bSopenharmony_ci                                            [data, ix](auto selfObject) {
2348bf80f4bSopenharmony_ci                                                if (auto self = static_pointer_cast<MultiMeshImpl>(selfObject)) {
2358bf80f4bSopenharmony_ci                                                    if (auto sceneHolder = self->sceneHolder_.lock()) {
2368bf80f4bSopenharmony_ci                                                        CORE_NS::Entity mm;
2378bf80f4bSopenharmony_ci                                                        mm.id = self->handle_;
2388bf80f4bSopenharmony_ci                                                        sceneHolder->SetTransformation(mm, ix, data);
2398bf80f4bSopenharmony_ci                                                    }
2408bf80f4bSopenharmony_ci                                                }
2418bf80f4bSopenharmony_ci                                                return false;
2428bf80f4bSopenharmony_ci                                            },
2438bf80f4bSopenharmony_ci                                            weak),
2448bf80f4bSopenharmony_ci                                        false);
2458bf80f4bSopenharmony_ci                                }
2468bf80f4bSopenharmony_ci                            }
2478bf80f4bSopenharmony_ci                        }
2488bf80f4bSopenharmony_ci                    }
2498bf80f4bSopenharmony_ci                }),
2508bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));
2518bf80f4bSopenharmony_ci        */
2528bf80f4bSopenharmony_ci        return true;
2538bf80f4bSopenharmony_ci    }
2548bf80f4bSopenharmony_ci};
2558bf80f4bSopenharmony_ci} // namespace
2568bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE()
2578bf80f4bSopenharmony_civoid RegisterMultiMeshImpl()
2588bf80f4bSopenharmony_ci{
2598bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().RegisterObjectType<MultiMeshImpl>();
2608bf80f4bSopenharmony_ci}
2618bf80f4bSopenharmony_civoid UnregisterMultiMeshImpl()
2628bf80f4bSopenharmony_ci{
2638bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().UnregisterObjectType<MultiMeshImpl>();
2648bf80f4bSopenharmony_ci}
2658bf80f4bSopenharmony_ci
2668bf80f4bSopenharmony_ciSCENE_END_NAMESPACE()