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/material_uid.h>
168bf80f4bSopenharmony_ci#include <scene_plugin/api/mesh_uid.h>
178bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_material.h>
188bf80f4bSopenharmony_ci
198bf80f4bSopenharmony_ci#include <meta/ext/concrete_base_object.h>
208bf80f4bSopenharmony_ci#include <meta/ext/implementation_macros.h>
218bf80f4bSopenharmony_ci
228bf80f4bSopenharmony_ci#include "bind_templates.inl"
238bf80f4bSopenharmony_ci#include "intf_submesh_bridge.h"
248bf80f4bSopenharmony_ci#include "node_impl.h"
258bf80f4bSopenharmony_ci#include "submesh_handler_uid.h"
268bf80f4bSopenharmony_ci#include "task_utils.h"
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask;
298bf80f4bSopenharmony_ci#include "intf_submesh_bridge.h"
308bf80f4bSopenharmony_ci
318bf80f4bSopenharmony_cinamespace {
328bf80f4bSopenharmony_ciclass MeshImpl
338bf80f4bSopenharmony_ci    : public META_NS::ConcreteBaseMetaObjectFwd<MeshImpl, NodeImpl, SCENE_NS::ClassId::Mesh, SCENE_NS::IMesh> {
348bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view MESH_COMPONENT_NAME = "MeshComponent";
358bf80f4bSopenharmony_ci    static constexpr size_t MESH_COMPONENT_NAME_LEN = MESH_COMPONENT_NAME.size() + 1;
368bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view MESH_AABBMIN = "MeshComponent.aabbMin";
378bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view MESH_AABBMAX = "MeshComponent.aabbMax";
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ci    bool Build(const IMetadata::Ptr& data) override
408bf80f4bSopenharmony_ci    {
418bf80f4bSopenharmony_ci        bool ret = false;
428bf80f4bSopenharmony_ci        if (ret = NodeImpl::Build(data); ret) {
438bf80f4bSopenharmony_ci            PropertyNameMask()[MESH_COMPONENT_NAME] = { MESH_AABBMIN.substr(MESH_COMPONENT_NAME_LEN),
448bf80f4bSopenharmony_ci                MESH_AABBMAX.substr(MESH_COMPONENT_NAME_LEN) };
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_ci            // subscribe material changes
478bf80f4bSopenharmony_ci            MaterialOverride()->OnChanged()->AddHandler(
488bf80f4bSopenharmony_ci                META_NS::MakeCallback<META_NS::IOnChanged>([this]() { SyncMaterialOverrideToSubmeshes(); }));
498bf80f4bSopenharmony_ci        }
508bf80f4bSopenharmony_ci        return ret;
518bf80f4bSopenharmony_ci    }
528bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(
538bf80f4bSopenharmony_ci        SCENE_NS::IMesh, SCENE_NS::IMaterial::Ptr, MaterialOverride, {}, )
548bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IMesh, BASE_NS::string, MaterialOverrideUri, {},
558bf80f4bSopenharmony_ci        META_NS::DEFAULT_PROPERTY_FLAGS | META_NS::ObjectFlagBits::INTERNAL)
568bf80f4bSopenharmony_ci
578bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_ARRAY_PROPERTY(
588bf80f4bSopenharmony_ci        SCENE_NS::IMesh, SCENE_NS::ISubMesh::Ptr, SubMeshes, {}, )
598bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IMesh, BASE_NS::Math::Vec3, AABBMin,
608bf80f4bSopenharmony_ci        BASE_NS::Math::Vec3(0.f, 0.f, 0.f), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
618bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IMesh, BASE_NS::Math::Vec3, AABBMax,
628bf80f4bSopenharmony_ci        BASE_NS::Math::Vec3(0.f, 0.f, 0.f), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
638bf80f4bSopenharmony_ci
648bf80f4bSopenharmony_ci    void SyncMaterialOverrideToSubmeshes()
658bf80f4bSopenharmony_ci    {
668bf80f4bSopenharmony_ci        auto material = MaterialOverride()->GetValue();
678bf80f4bSopenharmony_ci        if (material) {
688bf80f4bSopenharmony_ci
698bf80f4bSopenharmony_ci            for (auto& submesh : SubMeshes()->GetValue()) {
708bf80f4bSopenharmony_ci                auto submeshPrivate = interface_cast<SCENE_NS::ISubMeshPrivate>(submesh);
718bf80f4bSopenharmony_ci                if (submeshPrivate) {
728bf80f4bSopenharmony_ci                    submeshPrivate->SetOverrideMaterial(material);
738bf80f4bSopenharmony_ci                }
748bf80f4bSopenharmony_ci            }
758bf80f4bSopenharmony_ci        } else {
768bf80f4bSopenharmony_ci            META_ACCESS_PROPERTY(MaterialOverrideUri)->SetValue({});
778bf80f4bSopenharmony_ci            // Reset submeshes back to original value.
788bf80f4bSopenharmony_ci            for (auto& submesh : SubMeshes()->GetValue()) {
798bf80f4bSopenharmony_ci                auto submeshPrivate = interface_cast<SCENE_NS::ISubMeshPrivate>(submesh);
808bf80f4bSopenharmony_ci                if (submeshPrivate) {
818bf80f4bSopenharmony_ci                    submeshPrivate->SetOverrideMaterial({});
828bf80f4bSopenharmony_ci                }
838bf80f4bSopenharmony_ci            }
848bf80f4bSopenharmony_ci        }
858bf80f4bSopenharmony_ci    }
868bf80f4bSopenharmony_ci
878bf80f4bSopenharmony_ci    bool CompleteInitialization(const BASE_NS::string& path) override
888bf80f4bSopenharmony_ci    {
898bf80f4bSopenharmony_ci        if (!NodeImpl::CompleteInitialization(path)) {
908bf80f4bSopenharmony_ci            return false;
918bf80f4bSopenharmony_ci        }
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_ci        // Ensure override material is connected to ecs.
948bf80f4bSopenharmony_ci        auto overrideMaterial = GetValue(MaterialOverride());
958bf80f4bSopenharmony_ci        if (overrideMaterial) {
968bf80f4bSopenharmony_ci            BindObject(interface_pointer_cast<INode>(overrideMaterial));
978bf80f4bSopenharmony_ci        }
988bf80f4bSopenharmony_ci
998bf80f4bSopenharmony_ci        // Ensure submesh materials are connected to ecs.
1008bf80f4bSopenharmony_ci        auto submeshes = META_ACCESS_PROPERTY(SubMeshes)->GetValue();
1018bf80f4bSopenharmony_ci        for (auto i = 0; i < submeshes.size(); ++i) {
1028bf80f4bSopenharmony_ci            auto submesh = submeshes.at(i);
1038bf80f4bSopenharmony_ci            auto material = META_NS::GetValue(submesh->Material());
1048bf80f4bSopenharmony_ci            if (material) {
1058bf80f4bSopenharmony_ci                BindObject(interface_pointer_cast<INode>(material));
1068bf80f4bSopenharmony_ci            }
1078bf80f4bSopenharmony_ci        }
1088bf80f4bSopenharmony_ci
1098bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
1108bf80f4bSopenharmony_ci        BindChanges(propHandler_, META_ACCESS_PROPERTY(AABBMin), meta, MESH_AABBMIN);
1118bf80f4bSopenharmony_ci        BindChanges(propHandler_, META_ACCESS_PROPERTY(AABBMax), meta, MESH_AABBMAX);
1128bf80f4bSopenharmony_ci
1138bf80f4bSopenharmony_ci        if (auto ecs = EcsScene()->GetEcs()) {
1148bf80f4bSopenharmony_ci            submeshHandler_ = GetObjectRegistry().Create<SCENE_NS::ISubMeshBridge>(SCENE_NS::ClassId::SubMeshHandler);
1158bf80f4bSopenharmony_ci            submeshHandler_->Initialize(CORE_NS::GetManager<CORE3D_NS::IMeshComponentManager>(*ecs),
1168bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), META_ACCESS_PROPERTY(SubMeshes), GetSelf<INodeEcsInterfacePrivate>());
1178bf80f4bSopenharmony_ci        }
1188bf80f4bSopenharmony_ci
1198bf80f4bSopenharmony_ci        // Ok, the initialization has reached the point where we have a scene and ecs initialized
1208bf80f4bSopenharmony_ci        // check if we have material URIs that should be progressed before we sync the status with ecs
1218bf80f4bSopenharmony_ci        auto materialOverrideUri = MaterialOverrideUri()->GetValue();
1228bf80f4bSopenharmony_ci        if (!materialOverrideUri.empty()) {
1238bf80f4bSopenharmony_ci            SCENE_NS::IMaterial::Ptr material = GetScene()->GetMaterial(materialOverrideUri);
1248bf80f4bSopenharmony_ci            if (material) {
1258bf80f4bSopenharmony_ci                MaterialOverride()->SetValue(material);
1268bf80f4bSopenharmony_ci            }
1278bf80f4bSopenharmony_ci        }
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci        // Update material override.
1308bf80f4bSopenharmony_ci        SyncMaterialOverrideToSubmeshes();
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_ci        // Also restore submesh materials.
1338bf80f4bSopenharmony_ci        for (auto i = 0; i < submeshes.size(); ++i) {
1348bf80f4bSopenharmony_ci            auto submesh = submeshes.at(i);
1358bf80f4bSopenharmony_ci            auto materialUri = META_NS::GetValue(submesh->MaterialUri());
1368bf80f4bSopenharmony_ci            if (!materialUri.empty()) {
1378bf80f4bSopenharmony_ci                submesh->Material()->SetValue(GetScene()->GetMaterial(materialUri));
1388bf80f4bSopenharmony_ci            }
1398bf80f4bSopenharmony_ci        }
1408bf80f4bSopenharmony_ci        return true;
1418bf80f4bSopenharmony_ci    }
1428bf80f4bSopenharmony_ci
1438bf80f4bSopenharmony_ci    void SetPath(const BASE_NS::string& path, const BASE_NS::string& name, CORE_NS::Entity entity) override
1448bf80f4bSopenharmony_ci    {
1458bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Path)->SetValue(path);
1468bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Name)->SetValue(name);
1478bf80f4bSopenharmony_ci
1488bf80f4bSopenharmony_ci        if (auto iscene = GetScene()) {
1498bf80f4bSopenharmony_ci            iscene->UpdateCachedReference(GetSelf<SCENE_NS::INode>());
1508bf80f4bSopenharmony_ci        }
1518bf80f4bSopenharmony_ci        if (auto scene = EcsScene()) {
1528bf80f4bSopenharmony_ci            SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTING);
1538bf80f4bSopenharmony_ci            initializeTaskToken_ = scene->AddEngineTask(
1548bf80f4bSopenharmony_ci                MakeTask(
1558bf80f4bSopenharmony_ci                    [name, fullpath = path + name](auto selfObject) {
1568bf80f4bSopenharmony_ci                        if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
1578bf80f4bSopenharmony_ci                            if (auto sceneHolder = self->SceneHolder()) {
1588bf80f4bSopenharmony_ci                                CORE_NS::Entity meshEntinty {};
1598bf80f4bSopenharmony_ci                                if (sceneHolder->FindMesh(name, fullpath, meshEntinty)) {
1608bf80f4bSopenharmony_ci                                    SCENE_PLUGIN_VERBOSE_LOG("binding mesh: %s", name.c_str());
1618bf80f4bSopenharmony_ci                                    if (auto proxyIf =
1628bf80f4bSopenharmony_ci                                            interface_pointer_cast<SCENE_NS::IEcsProxyObject>(self->EcsObject())) {
1638bf80f4bSopenharmony_ci                                        proxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener());
1648bf80f4bSopenharmony_ci                                    }
1658bf80f4bSopenharmony_ci                                    self->EcsObject()->DefineTargetProperties(self->PropertyNameMask());
1668bf80f4bSopenharmony_ci                                    self->EcsObject()->SetEntity(sceneHolder->GetEcs(), meshEntinty);
1678bf80f4bSopenharmony_ci                                    sceneHolder->QueueApplicationTask(
1688bf80f4bSopenharmony_ci                                        MakeTask(
1698bf80f4bSopenharmony_ci                                            [name](auto selfObject) {
1708bf80f4bSopenharmony_ci                                                if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
1718bf80f4bSopenharmony_ci                                                    self->CompleteInitialization(name);
1728bf80f4bSopenharmony_ci                                                    self->SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTED);
1738bf80f4bSopenharmony_ci                                                    if (auto node =
1748bf80f4bSopenharmony_ci                                                            interface_pointer_cast<SCENE_NS::INode>(selfObject)) {
1758bf80f4bSopenharmony_ci                                                        META_NS::Invoke<META_NS::IOnChanged>(node->OnLoaded());
1768bf80f4bSopenharmony_ci                                                    }
1778bf80f4bSopenharmony_ci                                                }
1788bf80f4bSopenharmony_ci                                                return false;
1798bf80f4bSopenharmony_ci                                            },
1808bf80f4bSopenharmony_ci                                            selfObject),
1818bf80f4bSopenharmony_ci                                        false);
1828bf80f4bSopenharmony_ci                                } else {
1838bf80f4bSopenharmony_ci                                    CORE_LOG_D("Could not find '%s' mesh", name.c_str());
1848bf80f4bSopenharmony_ci                                    sceneHolder->QueueApplicationTask(
1858bf80f4bSopenharmony_ci                                        MakeTask(
1868bf80f4bSopenharmony_ci                                            [](auto selfObject) {
1878bf80f4bSopenharmony_ci                                                if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
1888bf80f4bSopenharmony_ci                                                    self->SetStatus(SCENE_NS::INode::NODE_STATUS_DISCONNECTED);
1898bf80f4bSopenharmony_ci                                                }
1908bf80f4bSopenharmony_ci                                                return false;
1918bf80f4bSopenharmony_ci                                            },
1928bf80f4bSopenharmony_ci                                            selfObject),
1938bf80f4bSopenharmony_ci                                        false);
1948bf80f4bSopenharmony_ci                                }
1958bf80f4bSopenharmony_ci                            }
1968bf80f4bSopenharmony_ci                        }
1978bf80f4bSopenharmony_ci                        return false;
1988bf80f4bSopenharmony_ci                    },
1998bf80f4bSopenharmony_ci                    GetSelf()),
2008bf80f4bSopenharmony_ci                false);
2018bf80f4bSopenharmony_ci        }
2028bf80f4bSopenharmony_ci    }
2038bf80f4bSopenharmony_ci
2048bf80f4bSopenharmony_ci    bool BuildChildren(SCENE_NS::INode::BuildBehavior) override
2058bf80f4bSopenharmony_ci    {
2068bf80f4bSopenharmony_ci        // in typical cases we should not have children
2078bf80f4bSopenharmony_ci        if (META_NS::GetValue(META_ACCESS_PROPERTY(Status)) == SCENE_NS::INode::NODE_STATUS_CONNECTED) {
2088bf80f4bSopenharmony_ci            SetStatus(SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
2098bf80f4bSopenharmony_ci            META_NS::Invoke<META_NS::IOnChanged>(OnBound());
2108bf80f4bSopenharmony_ci            bound_ = true;
2118bf80f4bSopenharmony_ci        }
2128bf80f4bSopenharmony_ci        return true;
2138bf80f4bSopenharmony_ci    }
2148bf80f4bSopenharmony_ci
2158bf80f4bSopenharmony_ci    bool ShouldExport() const override
2168bf80f4bSopenharmony_ci    {
2178bf80f4bSopenharmony_ci        for (auto& submesh : SubMeshes()->GetValue()) {
2188bf80f4bSopenharmony_ci            auto meta = interface_pointer_cast<META_NS::IMetadata>(submesh);
2198bf80f4bSopenharmony_ci            if (HasChangedProperties(*meta)) {
2208bf80f4bSopenharmony_ci                return true;
2218bf80f4bSopenharmony_ci            }
2228bf80f4bSopenharmony_ci        }
2238bf80f4bSopenharmony_ci        return false;
2248bf80f4bSopenharmony_ci    }
2258bf80f4bSopenharmony_ci    //todo
2268bf80f4bSopenharmony_ci    /*
2278bf80f4bSopenharmony_ci    bool Export(
2288bf80f4bSopenharmony_ci        META_NS::Serialization::IExportContext& context, META_NS::Serialization::ClassPrimitive& value) const override
2298bf80f4bSopenharmony_ci    {
2308bf80f4bSopenharmony_ci        BASE_NS::vector<SCENE_NS::IMaterial::Ptr> nonSerializedMaterials;
2318bf80f4bSopenharmony_ci
2328bf80f4bSopenharmony_ci        auto hasOverrideMaterialUri = !GetValue(MaterialOverrideUri()).empty();
2338bf80f4bSopenharmony_ci        auto overrideMaterial = GetValue(MaterialOverride());
2348bf80f4bSopenharmony_ci        if (overrideMaterial && hasOverrideMaterialUri) {
2358bf80f4bSopenharmony_ci            if (interface_pointer_cast<META_NS::IObjectFlags>(overrideMaterial)->GetObjectFlags() &
2368bf80f4bSopenharmony_ci                META_NS::ObjectFlagBits::SERIALIZE) {
2378bf80f4bSopenharmony_ci                nonSerializedMaterials.push_back(overrideMaterial);
2388bf80f4bSopenharmony_ci            }
2398bf80f4bSopenharmony_ci        }
2408bf80f4bSopenharmony_ci
2418bf80f4bSopenharmony_ci        for (auto& submesh : SubMeshes()->ToVector()) {
2428bf80f4bSopenharmony_ci            auto hasSubmeshMaterialUri = !GetValue(submesh->MaterialUri()).empty();
2438bf80f4bSopenharmony_ci            auto submeshMaterial = GetValue(submesh->Material());
2448bf80f4bSopenharmony_ci            if (submeshMaterial && hasSubmeshMaterialUri) {
2458bf80f4bSopenharmony_ci                if (interface_pointer_cast<META_NS::IObjectFlags>(submeshMaterial)->GetObjectFlags() &
2468bf80f4bSopenharmony_ci                    META_NS::ObjectFlagBits::SERIALIZE) {
2478bf80f4bSopenharmony_ci                    nonSerializedMaterials.push_back(submeshMaterial);
2488bf80f4bSopenharmony_ci                }
2498bf80f4bSopenharmony_ci            }
2508bf80f4bSopenharmony_ci        }
2518bf80f4bSopenharmony_ci
2528bf80f4bSopenharmony_ci        // Do not export these materials.
2538bf80f4bSopenharmony_ci        for (auto& material : nonSerializedMaterials) {
2548bf80f4bSopenharmony_ci            META_NS::SetObjectFlags(material, META_NS::ObjectFlagBits::SERIALIZE, false);
2558bf80f4bSopenharmony_ci        }
2568bf80f4bSopenharmony_ci
2578bf80f4bSopenharmony_ci        bool result = Fwd::Export(context, value);
2588bf80f4bSopenharmony_ci
2598bf80f4bSopenharmony_ci        // Put back material serialization info.
2608bf80f4bSopenharmony_ci        for (auto& material : nonSerializedMaterials) {
2618bf80f4bSopenharmony_ci            META_NS::SetObjectFlags(material, META_NS::ObjectFlagBits::SERIALIZE, true);
2628bf80f4bSopenharmony_ci        }
2638bf80f4bSopenharmony_ci
2648bf80f4bSopenharmony_ci        return result;
2658bf80f4bSopenharmony_ci    }
2668bf80f4bSopenharmony_ci    */
2678bf80f4bSopenharmony_ci    // Set given material for all the submeshes.
2688bf80f4bSopenharmony_ci    void SetMaterial(const SCENE_NS::IMaterial::Ptr material) override
2698bf80f4bSopenharmony_ci    {
2708bf80f4bSopenharmony_ci        MaterialOverride()->SetValue(material);
2718bf80f4bSopenharmony_ci    }
2728bf80f4bSopenharmony_ci
2738bf80f4bSopenharmony_ci    // Set material for the spesific submesh.
2748bf80f4bSopenharmony_ci    void SetMaterial(size_t index, const SCENE_NS::IMaterial::Ptr& material) override
2758bf80f4bSopenharmony_ci    {
2768bf80f4bSopenharmony_ci        if (auto node = interface_pointer_cast<SCENE_NS::INode>(material)) {
2778bf80f4bSopenharmony_ci            node->Status()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(
2788bf80f4bSopenharmony_ci                [mat = BASE_NS::weak_ptr(material)](const auto& self, const auto& status, const auto& index) {
2798bf80f4bSopenharmony_ci                    if (self && status && status->GetValue() == SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED) {
2808bf80f4bSopenharmony_ci                        static_cast<MeshImpl*>(self.get())->SetMaterialToScene((int32_t)index, mat.lock());
2818bf80f4bSopenharmony_ci                    }
2828bf80f4bSopenharmony_ci                },
2838bf80f4bSopenharmony_ci                GetSelf(), node->Status(), index));
2848bf80f4bSopenharmony_ci            if (auto status = META_NS::GetValue(node->Status());
2858bf80f4bSopenharmony_ci                status == SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED ||
2868bf80f4bSopenharmony_ci                status == SCENE_NS::INode::NODE_STATUS_CONNECTED) {
2878bf80f4bSopenharmony_ci                SetMaterialToScene(static_cast<int64_t>(index), material);
2888bf80f4bSopenharmony_ci            }
2898bf80f4bSopenharmony_ci        }
2908bf80f4bSopenharmony_ci    }
2918bf80f4bSopenharmony_ci
2928bf80f4bSopenharmony_ci    void SetMaterialToScene(int64_t index, const SCENE_NS::IMaterial::Ptr& material)
2938bf80f4bSopenharmony_ci    {
2948bf80f4bSopenharmony_ci        auto count = SubMeshes()->GetSize();
2958bf80f4bSopenharmony_ci        if (index == -1) {
2968bf80f4bSopenharmony_ci            for (auto i = 0; i < count; ++i) {
2978bf80f4bSopenharmony_ci                SubMeshes()->GetValueAt(i)->SetMaterial(material);
2988bf80f4bSopenharmony_ci            }
2998bf80f4bSopenharmony_ci        } else if (index < count) {
3008bf80f4bSopenharmony_ci            SubMeshes()->GetValueAt(index)->SetMaterial(material);
3018bf80f4bSopenharmony_ci        }
3028bf80f4bSopenharmony_ci    }
3038bf80f4bSopenharmony_ci
3048bf80f4bSopenharmony_ci    SCENE_NS::IMaterial::Ptr GetMaterial(size_t index) override
3058bf80f4bSopenharmony_ci    {
3068bf80f4bSopenharmony_ci        if (index < META_ACCESS_PROPERTY(SubMeshes)->GetSize()) {
3078bf80f4bSopenharmony_ci            return META_ACCESS_PROPERTY(SubMeshes)->GetValueAt(index)->Material()->GetValue();
3088bf80f4bSopenharmony_ci        }
3098bf80f4bSopenharmony_ci
3108bf80f4bSopenharmony_ci        SCENE_NS::IMaterial::Ptr ret {};
3118bf80f4bSopenharmony_ci        if (auto iscene = GetScene()) {
3128bf80f4bSopenharmony_ci            if (META_NS::GetValue(iscene->Asynchronous()) == false) {
3138bf80f4bSopenharmony_ci                auto entityName = SceneHolder()->GetMaterialName(EcsObject()->GetEntity(), index);
3148bf80f4bSopenharmony_ci                if (!entityName.empty()) {
3158bf80f4bSopenharmony_ci                    ret = iscene->GetMaterial(entityName);
3168bf80f4bSopenharmony_ci                }
3178bf80f4bSopenharmony_ci            }
3188bf80f4bSopenharmony_ci        }
3198bf80f4bSopenharmony_ci
3208bf80f4bSopenharmony_ci        // This path is not needed if material exists, in async mode it could still save the day, though
3218bf80f4bSopenharmony_ci        if (!ret) {
3228bf80f4bSopenharmony_ci            ret = GetObjectRegistry().Create<SCENE_NS::IMaterial>(SCENE_NS::ClassId::Material);
3238bf80f4bSopenharmony_ci
3248bf80f4bSopenharmony_ci            if (auto scene = EcsScene()) {
3258bf80f4bSopenharmony_ci                scene->AddEngineTask(
3268bf80f4bSopenharmony_ci                    MakeTask(
3278bf80f4bSopenharmony_ci                        [ret, index](auto selfObject) {
3288bf80f4bSopenharmony_ci                            if (auto self = interface_pointer_cast<SCENE_NS::IEcsObject>(selfObject)) {
3298bf80f4bSopenharmony_ci                                if (auto node = static_pointer_cast<NodeImpl>(selfObject)) {
3308bf80f4bSopenharmony_ci                                    if (auto sceneHolder = node->SceneHolder()) {
3318bf80f4bSopenharmony_ci                                        auto entityName = sceneHolder->GetMaterialName(self->GetEntity(), index);
3328bf80f4bSopenharmony_ci                                        if (!entityName.empty()) {
3338bf80f4bSopenharmony_ci                                            BASE_NS::string name(entityName.data(), entityName.size());
3348bf80f4bSopenharmony_ci                                            sceneHolder->QueueApplicationTask(
3358bf80f4bSopenharmony_ci                                                MakeTask(
3368bf80f4bSopenharmony_ci                                                    [name, ret](auto selfObject) {
3378bf80f4bSopenharmony_ci                                                        if (auto node = static_pointer_cast<NodeImpl>(selfObject)) {
3388bf80f4bSopenharmony_ci                                                            auto scene = node->EcsScene();
3398bf80f4bSopenharmony_ci                                                            auto object = META_NS::GetObjectRegistry().Create(
3408bf80f4bSopenharmony_ci                                                                SCENE_NS::ClassId::EcsObject);
3418bf80f4bSopenharmony_ci                                                            if (auto ecsObject =
3428bf80f4bSopenharmony_ci                                                                    interface_pointer_cast<SCENE_NS::IEcsObject>(
3438bf80f4bSopenharmony_ci                                                                        object)) {
3448bf80f4bSopenharmony_ci                                                                if (auto privateInit = interface_pointer_cast<
3458bf80f4bSopenharmony_ci                                                                        INodeEcsInterfacePrivate>(ret)) {
3468bf80f4bSopenharmony_ci                                                                    privateInit->Initialize(scene, ecsObject, {}, "",
3478bf80f4bSopenharmony_ci                                                                        name, node->SceneHolder(), {});
3488bf80f4bSopenharmony_ci                                                                }
3498bf80f4bSopenharmony_ci                                                            }
3508bf80f4bSopenharmony_ci                                                        }
3518bf80f4bSopenharmony_ci                                                        return false;
3528bf80f4bSopenharmony_ci                                                    },
3538bf80f4bSopenharmony_ci                                                    selfObject),
3548bf80f4bSopenharmony_ci                                                false);
3558bf80f4bSopenharmony_ci                                        }
3568bf80f4bSopenharmony_ci                                    }
3578bf80f4bSopenharmony_ci                                }
3588bf80f4bSopenharmony_ci                            }
3598bf80f4bSopenharmony_ci                            return false;
3608bf80f4bSopenharmony_ci                        },
3618bf80f4bSopenharmony_ci                        GetSelf()),
3628bf80f4bSopenharmony_ci                    false);
3638bf80f4bSopenharmony_ci            }
3648bf80f4bSopenharmony_ci        }
3658bf80f4bSopenharmony_ci        return ret;
3668bf80f4bSopenharmony_ci    }
3678bf80f4bSopenharmony_ci
3688bf80f4bSopenharmony_ci    void SetRenderSortLayerOrder(size_t index, uint8_t value) override
3698bf80f4bSopenharmony_ci    {
3708bf80f4bSopenharmony_ci        if (submeshHandler_) {
3718bf80f4bSopenharmony_ci            submeshHandler_->SetRenderSortLayerOrder(index, value);
3728bf80f4bSopenharmony_ci        } else {
3738bf80f4bSopenharmony_ci            CORE_LOG_W("%s: mesh is not ready yet, call has no effect", __func__);
3748bf80f4bSopenharmony_ci        }
3758bf80f4bSopenharmony_ci    }
3768bf80f4bSopenharmony_ci
3778bf80f4bSopenharmony_ci    uint8_t GetRenderSortLayerOrder(size_t index) const override
3788bf80f4bSopenharmony_ci    {
3798bf80f4bSopenharmony_ci        if (index < SubMeshes()->GetSize()) {
3808bf80f4bSopenharmony_ci            return META_NS::GetValue(SubMeshes()->GetValueAt(index)->RenderSortLayerOrder());
3818bf80f4bSopenharmony_ci        }
3828bf80f4bSopenharmony_ci        return 0u; // default in mesh component
3838bf80f4bSopenharmony_ci    }
3848bf80f4bSopenharmony_ci
3858bf80f4bSopenharmony_ci    template<typename INDEX_TYPE>
3868bf80f4bSopenharmony_ci    void UpdateMeshFromArrays(
3878bf80f4bSopenharmony_ci        SCENE_NS::MeshGeometryArrayPtr<INDEX_TYPE> arrays, const RENDER_NS::IndexType& indexType, bool append = false)
3888bf80f4bSopenharmony_ci    {
3898bf80f4bSopenharmony_ci        if (auto sh = SceneHolder()) {
3908bf80f4bSopenharmony_ci            if (!append) {
3918bf80f4bSopenharmony_ci                // Need to invalidate materials up front
3928bf80f4bSopenharmony_ci                SetMaterial(SCENE_NS::IMaterial::Ptr {});
3938bf80f4bSopenharmony_ci            }
3948bf80f4bSopenharmony_ci            SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTING);
3958bf80f4bSopenharmony_ci            sh->QueueEngineTask(MakeTask(
3968bf80f4bSopenharmony_ci                                    [arrays, indexType, append](auto privateIntf) {
3978bf80f4bSopenharmony_ci                                        // create new mesh entity
3988bf80f4bSopenharmony_ci                                        if (auto sh = privateIntf->SceneHolder()) {
3998bf80f4bSopenharmony_ci                                            auto existingEntity = privateIntf->EcsObject()->GetEntity();
4008bf80f4bSopenharmony_ci                                            auto newEntity = sh->template CreateMeshFromArrays<INDEX_TYPE>(
4018bf80f4bSopenharmony_ci                                                "TempMesh", arrays, indexType, existingEntity, append);
4028bf80f4bSopenharmony_ci                                            sh->QueueApplicationTask(
4038bf80f4bSopenharmony_ci                                                MakeTask(
4048bf80f4bSopenharmony_ci                                                    [](auto strong) {
4058bf80f4bSopenharmony_ci                                                        if (auto self = static_cast<MeshImpl*>(strong.get())) {
4068bf80f4bSopenharmony_ci                                                            self->SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTED);
4078bf80f4bSopenharmony_ci                                                            self->SetStatus(
4088bf80f4bSopenharmony_ci                                                                SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
4098bf80f4bSopenharmony_ci                                                            if (META_NS::GetValue(self->MaterialOverride())) {
4108bf80f4bSopenharmony_ci                                                                self->SyncMaterialOverrideToSubmeshes();
4118bf80f4bSopenharmony_ci                                                            }
4128bf80f4bSopenharmony_ci                                                        }
4138bf80f4bSopenharmony_ci                                                        return false;
4148bf80f4bSopenharmony_ci                                                    },
4158bf80f4bSopenharmony_ci                                                    privateIntf),
4168bf80f4bSopenharmony_ci                                                false);
4178bf80f4bSopenharmony_ci                                        }
4188bf80f4bSopenharmony_ci                                        return false;
4198bf80f4bSopenharmony_ci                                    },
4208bf80f4bSopenharmony_ci                                    GetSelf<INodeEcsInterfacePrivate>()),
4218bf80f4bSopenharmony_ci                false);
4228bf80f4bSopenharmony_ci        }
4238bf80f4bSopenharmony_ci    }
4248bf80f4bSopenharmony_ci
4258bf80f4bSopenharmony_ci    void UpdateMeshFromArraysI16(SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays) override
4268bf80f4bSopenharmony_ci    {
4278bf80f4bSopenharmony_ci        UpdateMeshFromArrays<uint16_t>(arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT16);
4288bf80f4bSopenharmony_ci    }
4298bf80f4bSopenharmony_ci
4308bf80f4bSopenharmony_ci    void UpdateMeshFromArraysI32(SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays) override
4318bf80f4bSopenharmony_ci    {
4328bf80f4bSopenharmony_ci        UpdateMeshFromArrays<uint32_t>(arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT32);
4338bf80f4bSopenharmony_ci    }
4348bf80f4bSopenharmony_ci
4358bf80f4bSopenharmony_ci    void AddSubmeshesFromArrayI16(SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays) override
4368bf80f4bSopenharmony_ci    {
4378bf80f4bSopenharmony_ci        UpdateMeshFromArrays<uint16_t>(arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT16, true);
4388bf80f4bSopenharmony_ci    }
4398bf80f4bSopenharmony_ci
4408bf80f4bSopenharmony_ci    void AddSubmeshesFromArraysI32(SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays) override
4418bf80f4bSopenharmony_ci    {
4428bf80f4bSopenharmony_ci        UpdateMeshFromArrays<uint32_t>(arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT32, true);
4438bf80f4bSopenharmony_ci    }
4448bf80f4bSopenharmony_ci
4458bf80f4bSopenharmony_ci    void CloneSubmesh(SCENE_NS::ISubMesh::Ptr submesh) override
4468bf80f4bSopenharmony_ci    {
4478bf80f4bSopenharmony_ci        if (auto sh = SceneHolder()) {
4488bf80f4bSopenharmony_ci            sh->QueueEngineTask(MakeTask(
4498bf80f4bSopenharmony_ci                                    [source = interface_pointer_cast<SCENE_NS::ISubMeshPrivate>(submesh)->GetEntity(),
4508bf80f4bSopenharmony_ci                                        index = META_NS::GetValue(submesh->Handle())](auto privateIntf) {
4518bf80f4bSopenharmony_ci                                        privateIntf->SceneHolder()->CopySubMesh(
4528bf80f4bSopenharmony_ci                                            privateIntf->EcsObject()->GetEntity(), source, index);
4538bf80f4bSopenharmony_ci
4548bf80f4bSopenharmony_ci                                        return false;
4558bf80f4bSopenharmony_ci                                    },
4568bf80f4bSopenharmony_ci                                    GetSelf<INodeEcsInterfacePrivate>()),
4578bf80f4bSopenharmony_ci                false);
4588bf80f4bSopenharmony_ci        }
4598bf80f4bSopenharmony_ci        // Submesh bridge should automatically reflect the updates
4608bf80f4bSopenharmony_ci    }
4618bf80f4bSopenharmony_ci
4628bf80f4bSopenharmony_ci    void RemoveSubMesh(size_t index) override
4638bf80f4bSopenharmony_ci    {
4648bf80f4bSopenharmony_ci        if (submeshHandler_) {
4658bf80f4bSopenharmony_ci            submeshHandler_->RemoveSubmesh(index);
4668bf80f4bSopenharmony_ci        } else {
4678bf80f4bSopenharmony_ci            CORE_LOG_W("%s: mesh is not ready yet, call has no effect", __func__);
4688bf80f4bSopenharmony_ci        }
4698bf80f4bSopenharmony_ci    }
4708bf80f4bSopenharmony_ci    virtual void RemoveAllSubmeshes() override
4718bf80f4bSopenharmony_ci    {
4728bf80f4bSopenharmony_ci        if (submeshHandler_) {
4738bf80f4bSopenharmony_ci            submeshHandler_->RemoveSubmesh(-1);
4748bf80f4bSopenharmony_ci        } else {
4758bf80f4bSopenharmony_ci            CORE_LOG_W("%s: mesh is not ready yet, call has no effect", __func__);
4768bf80f4bSopenharmony_ci        }
4778bf80f4bSopenharmony_ci    }
4788bf80f4bSopenharmony_ci
4798bf80f4bSopenharmony_ciprivate:
4808bf80f4bSopenharmony_ci    SCENE_NS::ISubMeshBridge::Ptr submeshHandler_;
4818bf80f4bSopenharmony_ci};
4828bf80f4bSopenharmony_ci} // namespace
4838bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE()
4848bf80f4bSopenharmony_civoid RegisterMeshImpl()
4858bf80f4bSopenharmony_ci{
4868bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().RegisterObjectType<MeshImpl>();
4878bf80f4bSopenharmony_ci}
4888bf80f4bSopenharmony_civoid UnregisterMeshImpl()
4898bf80f4bSopenharmony_ci{
4908bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().UnregisterObjectType<MeshImpl>();
4918bf80f4bSopenharmony_ci}
4928bf80f4bSopenharmony_ci
4938bf80f4bSopenharmony_ciSCENE_END_NAMESPACE()
494