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 <3d/ecs/components/material_component.h>
178bf80f4bSopenharmony_ci#include <atomic>
188bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
198bf80f4bSopenharmony_ci#include <meta/interface/detail/array_property.h>
208bf80f4bSopenharmony_ci#include <meta/api/property/array_element_bind.h>
218bf80f4bSopenharmony_ci#include <meta/ext/concrete_base_object.h>
228bf80f4bSopenharmony_ci
238bf80f4bSopenharmony_ci#include "bind_templates.inl"
248bf80f4bSopenharmony_ci#include "intf_proxy_object_holder.h"
258bf80f4bSopenharmony_ci#include "node_impl.h"
268bf80f4bSopenharmony_ci#include "task_utils.h"
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ciusing CORE3D_NS::MaterialComponent;
298bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
308bf80f4bSopenharmony_ciMETA_TYPE(MaterialComponent::TextureInfo);
318bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
328bf80f4bSopenharmony_ci
338bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask;
348bf80f4bSopenharmony_ci#define GET_HOLDER(info) interface_pointer_cast<SCENE_NS::IProxyObjectHolder>(info)->Holder()
358bf80f4bSopenharmony_ci
368bf80f4bSopenharmony_cinamespace {
378bf80f4bSopenharmony_citemplate<typename... Types>
388bf80f4bSopenharmony_ciinline void BindMetaProperty(
398bf80f4bSopenharmony_ci    PropertyHandlerArrayHolder& handler, META_NS::IProperty::Ptr& clone, META_NS::IProperty::Ptr& prop)
408bf80f4bSopenharmony_ci{
418bf80f4bSopenharmony_ci    (BindIfCorrectType<Types>(handler, clone, prop) || ...);
428bf80f4bSopenharmony_ci}
438bf80f4bSopenharmony_ci
448bf80f4bSopenharmony_civoid BindMetaProperty(
458bf80f4bSopenharmony_ci    PropertyHandlerArrayHolder& handler, META_NS::IProperty::Ptr& clone, META_NS::IProperty::Ptr& prop)
468bf80f4bSopenharmony_ci{
478bf80f4bSopenharmony_ci    BindMetaProperty<BASE_NS::Math::Vec4, BASE_NS::Math::UVec4, BASE_NS::Math::IVec4, BASE_NS::Math::Vec3,
488bf80f4bSopenharmony_ci        BASE_NS::Math::UVec3, BASE_NS::Math::IVec3, BASE_NS::Math::Vec2, BASE_NS::Math::UVec2, BASE_NS::Math::IVec2,
498bf80f4bSopenharmony_ci        float, int32_t, uint32_t, BASE_NS::Math::Mat3X3, BASE_NS::Math::Mat4X4, bool, CORE_NS::Entity,
508bf80f4bSopenharmony_ci        CORE_NS::EntityReference>(handler, clone, prop);
518bf80f4bSopenharmony_ci}
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_cibool IsGltfResource(BASE_NS::string_view uri, BASE_NS::string_view resourcePath)
548bf80f4bSopenharmony_ci{
558bf80f4bSopenharmony_ci    // Image uris loaded form a glTF are in a format like this: "file://model.gltf/images/0"
568bf80f4bSopenharmony_ci
578bf80f4bSopenharmony_ci    // There must be an identifier string at the end of the uri after the '/'.
588bf80f4bSopenharmony_ci    const auto idSeparator = uri.find_last_of('/');
598bf80f4bSopenharmony_ci    if (idSeparator == BASE_NS::string_view::npos) {
608bf80f4bSopenharmony_ci        return false;
618bf80f4bSopenharmony_ci    }
628bf80f4bSopenharmony_ci
638bf80f4bSopenharmony_ci    // We don't care what is after the separator, but it should be preceded by <resourcePath>" e.g. /images".
648bf80f4bSopenharmony_ci    auto rest = uri.substr(0, idSeparator);
658bf80f4bSopenharmony_ci    if (!rest.ends_with(resourcePath)) {
668bf80f4bSopenharmony_ci        return false;
678bf80f4bSopenharmony_ci    }
688bf80f4bSopenharmony_ci    rest = rest.substr(0, rest.size() - resourcePath.size());
698bf80f4bSopenharmony_ci
708bf80f4bSopenharmony_ci    // Take the last 5 characters in lower case to check the extension.
718bf80f4bSopenharmony_ci    if (rest.size() < 5) {
728bf80f4bSopenharmony_ci        return false;
738bf80f4bSopenharmony_ci    }
748bf80f4bSopenharmony_ci    const auto extension = BASE_NS::string(rest.substr(rest.size() - 5, 5)).toLower();
758bf80f4bSopenharmony_ci    if (!extension.ends_with(".glb") && !extension.ends_with(".gltf")) {
768bf80f4bSopenharmony_ci        return false;
778bf80f4bSopenharmony_ci    }
788bf80f4bSopenharmony_ci
798bf80f4bSopenharmony_ci    return true;
808bf80f4bSopenharmony_ci}
818bf80f4bSopenharmony_ci
828bf80f4bSopenharmony_cibool IsGltfImage(BASE_NS::string_view uri)
838bf80f4bSopenharmony_ci{
848bf80f4bSopenharmony_ci    return IsGltfResource(uri, "/images");
858bf80f4bSopenharmony_ci}
868bf80f4bSopenharmony_ci
878bf80f4bSopenharmony_cibool IsGltfMaterial(BASE_NS::string_view uri)
888bf80f4bSopenharmony_ci{
898bf80f4bSopenharmony_ci    return IsGltfResource(uri, "/materials");
908bf80f4bSopenharmony_ci}
918bf80f4bSopenharmony_ci
928bf80f4bSopenharmony_ciclass MaterialImpl : public META_NS::ConcreteBaseMetaObjectFwd<MaterialImpl, NodeImpl, SCENE_NS::ClassId::Material,
938bf80f4bSopenharmony_ci                         SCENE_NS::IMaterial, ITextureStorage> {
948bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view MATERIAL_COMPONENT_NAME = "MaterialComponent";
958bf80f4bSopenharmony_ci
968bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view CUSTOM_PREFIX = "MaterialComponent.customProperties.";
978bf80f4bSopenharmony_ci    static constexpr size_t CUSTOM_PREFIX_SIZE = CUSTOM_PREFIX.size();
988bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view TEXTURE_PREFIX = "MaterialComponent.TextureInfo.";
998bf80f4bSopenharmony_ci    static constexpr size_t TEXTURE_PREFIX_SIZE = TEXTURE_PREFIX.size();
1008bf80f4bSopenharmony_ci
1018bf80f4bSopenharmony_ci    bool Build(const IMetadata::Ptr& data) override
1028bf80f4bSopenharmony_ci    {
1038bf80f4bSopenharmony_ci        bool ret = false;
1048bf80f4bSopenharmony_ci        if (ret = NodeImpl::Build(data); ret) {
1058bf80f4bSopenharmony_ci            // bind everything from material component, otherwise obey the wishes of other components
1068bf80f4bSopenharmony_ci            PropertyNameMask()[MATERIAL_COMPONENT_NAME] = {};
1078bf80f4bSopenharmony_ci            OnTypeChanged(); // initialize inputs
1088bf80f4bSopenharmony_ci        }
1098bf80f4bSopenharmony_ci        return ret;
1108bf80f4bSopenharmony_ci    }
1118bf80f4bSopenharmony_ci
1128bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, uint8_t, Type, 0)
1138bf80f4bSopenharmony_ci
1148bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, float, AlphaCutoff, 1.f)
1158bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, uint32_t, LightingFlags,
1168bf80f4bSopenharmony_ci        CORE3D_NS::MaterialComponent::LightingFlagBits::SHADOW_RECEIVER_BIT |
1178bf80f4bSopenharmony_ci            CORE3D_NS::MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT |
1188bf80f4bSopenharmony_ci            CORE3D_NS::MaterialComponent::LightingFlagBits::PUNCTUAL_LIGHT_RECEIVER_BIT |
1198bf80f4bSopenharmony_ci            CORE3D_NS::MaterialComponent::LightingFlagBits::INDIRECT_LIGHT_RECEIVER_BIT)
1208bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::IShader::Ptr, MaterialShader, {})
1218bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::IGraphicsState::Ptr, MaterialShaderState, {})
1228bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::IShader::Ptr, DepthShader, {})
1238bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::IGraphicsState::Ptr, DepthShaderState, {})
1248bf80f4bSopenharmony_ci
1258bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IMaterial, META_NS::IObject::Ptr, CustomProperties, {})
1268bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::ITextureInfo::Ptr, Inputs, {})
1278bf80f4bSopenharmony_ci    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IMaterial, SCENE_NS::ITextureInfo::Ptr, Textures, {})
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci
1308bf80f4bSopenharmony_ci    bool updatingInputs_ { false };
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_ci    void Activate() override
1338bf80f4bSopenharmony_ci    {
1348bf80f4bSopenharmony_ci        auto sceneHolder = SceneHolder();
1358bf80f4bSopenharmony_ci        if (!sceneHolder) {
1368bf80f4bSopenharmony_ci            return;
1378bf80f4bSopenharmony_ci        }
1388bf80f4bSopenharmony_ci
1398bf80f4bSopenharmony_ci        auto task = META_NS::MakeCallback<META_NS::ITaskQueueTask>(
1408bf80f4bSopenharmony_ci            [e = ecsObject_->GetEntity(), w = BASE_NS::weak_ptr(sceneHolder)] {
1418bf80f4bSopenharmony_ci                auto sh = w.lock();
1428bf80f4bSopenharmony_ci                if (sh) {
1438bf80f4bSopenharmony_ci                    sh->SetEntityActive(e, true);
1448bf80f4bSopenharmony_ci                }
1458bf80f4bSopenharmony_ci                return false;
1468bf80f4bSopenharmony_ci            });
1478bf80f4bSopenharmony_ci        sceneHolder->QueueEngineTask(task, false);
1488bf80f4bSopenharmony_ci    }
1498bf80f4bSopenharmony_ci
1508bf80f4bSopenharmony_ci    void Deactivate() override
1518bf80f4bSopenharmony_ci    {
1528bf80f4bSopenharmony_ci        auto sceneHolder = SceneHolder();
1538bf80f4bSopenharmony_ci        if (!sceneHolder) {
1548bf80f4bSopenharmony_ci            return;
1558bf80f4bSopenharmony_ci        }
1568bf80f4bSopenharmony_ci
1578bf80f4bSopenharmony_ci        auto task = META_NS::MakeCallback<META_NS::ITaskQueueTask>(
1588bf80f4bSopenharmony_ci            [e = ecsObject_->GetEntity(), w = BASE_NS::weak_ptr(sceneHolder)] {
1598bf80f4bSopenharmony_ci                auto sh = w.lock();
1608bf80f4bSopenharmony_ci                if (sh) {
1618bf80f4bSopenharmony_ci                    sh->SetEntityActive(e, false);
1628bf80f4bSopenharmony_ci                }
1638bf80f4bSopenharmony_ci                return false;
1648bf80f4bSopenharmony_ci            });
1658bf80f4bSopenharmony_ci        sceneHolder->QueueEngineTask(task, false);
1668bf80f4bSopenharmony_ci    }
1678bf80f4bSopenharmony_ci
1688bf80f4bSopenharmony_ci    void SetPath(const BASE_NS::string& path, const BASE_NS::string& name, CORE_NS::Entity entity) override
1698bf80f4bSopenharmony_ci    {
1708bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Path)->SetValue(path);
1718bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Name)->SetValue(name);
1728bf80f4bSopenharmony_ci
1738bf80f4bSopenharmony_ci        if (auto iscene = GetScene()) {
1748bf80f4bSopenharmony_ci            iscene->UpdateCachedReference(GetSelf<SCENE_NS::INode>());
1758bf80f4bSopenharmony_ci        }
1768bf80f4bSopenharmony_ci        if (auto scene = EcsScene()) {
1778bf80f4bSopenharmony_ci            SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTING);
1788bf80f4bSopenharmony_ci
1798bf80f4bSopenharmony_ci            initializeTaskToken_ = scene->AddEngineTask(MakeTask([me = BASE_NS::weak_ptr(GetSelf()),
1808bf80f4bSopenharmony_ci                                                                     materialName = name,
1818bf80f4bSopenharmony_ci                                                                     fullpath = path + name, entity]() {
1828bf80f4bSopenharmony_ci                if (auto self = static_pointer_cast<NodeImpl>(me.lock())) {
1838bf80f4bSopenharmony_ci                    if (auto sceneHolder = self->SceneHolder()) {
1848bf80f4bSopenharmony_ci                        CORE_NS::Entity materialEntity = entity;
1858bf80f4bSopenharmony_ci
1868bf80f4bSopenharmony_ci                        if (CORE_NS::EntityUtil::IsValid(materialEntity)) {
1878bf80f4bSopenharmony_ci                            SCENE_PLUGIN_VERBOSE_LOG("binding material: %s", materialName.c_str());
1888bf80f4bSopenharmony_ci                            if (auto proxyIf = interface_pointer_cast<SCENE_NS::IEcsProxyObject>(self->EcsObject())) {
1898bf80f4bSopenharmony_ci                                proxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener());
1908bf80f4bSopenharmony_ci                            }
1918bf80f4bSopenharmony_ci                            self->EcsObject()->DefineTargetProperties(self->PropertyNameMask());
1928bf80f4bSopenharmony_ci                            self->EcsObject()->SetEntity(sceneHolder->GetEcs(), materialEntity);
1938bf80f4bSopenharmony_ci                            sceneHolder->QueueApplicationTask(
1948bf80f4bSopenharmony_ci                                MakeTask(
1958bf80f4bSopenharmony_ci                                    [fullpath](auto selfObject) {
1968bf80f4bSopenharmony_ci                                        if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
1978bf80f4bSopenharmony_ci                                            self->CompleteInitialization(fullpath);
1988bf80f4bSopenharmony_ci                                            self->SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTED);
1998bf80f4bSopenharmony_ci                                            if (auto node = interface_pointer_cast<SCENE_NS::INode>(selfObject)) {
2008bf80f4bSopenharmony_ci                                                META_NS::Invoke<META_NS::IOnChanged>(node->OnLoaded());
2018bf80f4bSopenharmony_ci                                            }
2028bf80f4bSopenharmony_ci                                        }
2038bf80f4bSopenharmony_ci                                        return false;
2048bf80f4bSopenharmony_ci                                    },
2058bf80f4bSopenharmony_ci                                    me),
2068bf80f4bSopenharmony_ci                                false);
2078bf80f4bSopenharmony_ci                        } else {
2088bf80f4bSopenharmony_ci                            CORE_LOG_W("Could not find '%s' material", fullpath.c_str());
2098bf80f4bSopenharmony_ci                            sceneHolder->QueueApplicationTask(
2108bf80f4bSopenharmony_ci                                MakeTask(
2118bf80f4bSopenharmony_ci                                    [](auto selfObject) {
2128bf80f4bSopenharmony_ci                                        if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
2138bf80f4bSopenharmony_ci                                            self->SetStatus(SCENE_NS::INode::NODE_STATUS_DISCONNECTED);
2148bf80f4bSopenharmony_ci                                        }
2158bf80f4bSopenharmony_ci                                        return false;
2168bf80f4bSopenharmony_ci                                    },
2178bf80f4bSopenharmony_ci                                    me),
2188bf80f4bSopenharmony_ci                                false);
2198bf80f4bSopenharmony_ci                        }
2208bf80f4bSopenharmony_ci                    }
2218bf80f4bSopenharmony_ci                }
2228bf80f4bSopenharmony_ci                return false;
2238bf80f4bSopenharmony_ci            }),
2248bf80f4bSopenharmony_ci                false);
2258bf80f4bSopenharmony_ci        }
2268bf80f4bSopenharmony_ci    }
2278bf80f4bSopenharmony_ci
2288bf80f4bSopenharmony_cipublic: // ISerialization
2298bf80f4bSopenharmony_ci    void ApplyTextureInfoImage(size_t arrayIndex, SCENE_NS::ITextureInfo& info)
2308bf80f4bSopenharmony_ci    {
2318bf80f4bSopenharmony_ci        if (auto sceneHolder = SceneHolder()) {
2328bf80f4bSopenharmony_ci            bool shouldReset { true };
2338bf80f4bSopenharmony_ci            auto value = info.Image()->GetValue();
2348bf80f4bSopenharmony_ci            if (auto uriBitmap = interface_cast<SCENE_NS::IBitmap>(value)) {
2358bf80f4bSopenharmony_ci                auto uri = META_NS::GetValue(uriBitmap->Uri());
2368bf80f4bSopenharmony_ci                if (!uri.empty()) {
2378bf80f4bSopenharmony_ci                    shouldReset = false;
2388bf80f4bSopenharmony_ci
2398bf80f4bSopenharmony_ci                    if (IsGltfImage(uri)) {
2408bf80f4bSopenharmony_ci                        return;
2418bf80f4bSopenharmony_ci                    }
2428bf80f4bSopenharmony_ci
2438bf80f4bSopenharmony_ci                    sceneHolder->QueueEngineTask(
2448bf80f4bSopenharmony_ci                        MakeTask(
2458bf80f4bSopenharmony_ci                            [uri, entityId = EcsObject()->GetEntity().id, arrayIndex](auto sh) {
2468bf80f4bSopenharmony_ci                                CORE_NS::Entity target { entityId };
2478bf80f4bSopenharmony_ci                                auto image = sh->LoadImage(uri);
2488bf80f4bSopenharmony_ci                                sh->SetTexture(arrayIndex, target, image);
2498bf80f4bSopenharmony_ci
2508bf80f4bSopenharmony_ci                                return false;
2518bf80f4bSopenharmony_ci                            },
2528bf80f4bSopenharmony_ci                            sceneHolder),
2538bf80f4bSopenharmony_ci                        false);
2548bf80f4bSopenharmony_ci                }
2558bf80f4bSopenharmony_ci            }
2568bf80f4bSopenharmony_ci            if (shouldReset) {
2578bf80f4bSopenharmony_ci                sceneHolder->QueueEngineTask(MakeTask(
2588bf80f4bSopenharmony_ci                                                 [entity = EcsObject()->GetEntity(), arrayIndex](auto sh) {
2598bf80f4bSopenharmony_ci                                                     sh->SetTexture(arrayIndex, entity, {});
2608bf80f4bSopenharmony_ci                                                     return false;
2618bf80f4bSopenharmony_ci                                                 },
2628bf80f4bSopenharmony_ci                                                 sceneHolder),
2638bf80f4bSopenharmony_ci                    false);
2648bf80f4bSopenharmony_ci            }
2658bf80f4bSopenharmony_ci        }
2668bf80f4bSopenharmony_ci    }
2678bf80f4bSopenharmony_ci
2688bf80f4bSopenharmony_ci    void SubscribeToTextureInfo(size_t arrayIndex, SCENE_NS::ITextureInfo::Ptr info)
2698bf80f4bSopenharmony_ci    {
2708bf80f4bSopenharmony_ci        info->SetTextureSlotIndex(arrayIndex);
2718bf80f4bSopenharmony_ci
2728bf80f4bSopenharmony_ci        // EcsObject would provide use entity ref while we would like to use the enums to define which
2738bf80f4bSopenharmony_ci        // sampler to use Perhaps we create new factory method for scene-interface and then apply the direct
2748bf80f4bSopenharmony_ci        // biding from now on
2758bf80f4bSopenharmony_ci        GET_HOLDER(info)
2768bf80f4bSopenharmony_ci            .NewHandler(info->Sampler(), nullptr)
2778bf80f4bSopenharmony_ci            .Subscribe(info->Sampler(), [this, prop = info->Sampler(), arrayIndex]() {
2788bf80f4bSopenharmony_ci                if (auto sceneHolder = SceneHolder()) {
2798bf80f4bSopenharmony_ci                    sceneHolder->QueueEngineTask(
2808bf80f4bSopenharmony_ci                        MakeTask(
2818bf80f4bSopenharmony_ci                            [value = prop->GetValue(), entityId = EcsObject()->GetEntity().id, arrayIndex](auto sh) {
2828bf80f4bSopenharmony_ci                                CORE_NS::Entity target { entityId };
2838bf80f4bSopenharmony_ci                                sh->SetSampler(
2848bf80f4bSopenharmony_ci                                    arrayIndex, target, static_cast<SCENE_NS::ITextureInfo::SamplerId>(value));
2858bf80f4bSopenharmony_ci
2868bf80f4bSopenharmony_ci                                return false;
2878bf80f4bSopenharmony_ci                            },
2888bf80f4bSopenharmony_ci                            sceneHolder),
2898bf80f4bSopenharmony_ci                        false);
2908bf80f4bSopenharmony_ci                }
2918bf80f4bSopenharmony_ci            });
2928bf80f4bSopenharmony_ci
2938bf80f4bSopenharmony_ci        GET_HOLDER(info)
2948bf80f4bSopenharmony_ci            .NewHandler(info->Image(), nullptr)
2958bf80f4bSopenharmony_ci            .Subscribe(info->Image(),
2968bf80f4bSopenharmony_ci                [this, textureInfo = info.get(), arrayIndex]() { ApplyTextureInfoImage(arrayIndex, *textureInfo); });
2978bf80f4bSopenharmony_ci    }
2988bf80f4bSopenharmony_ci    /*
2998bf80f4bSopenharmony_ci    bool Export(
3008bf80f4bSopenharmony_ci        META_NS::Serialization::IExportContext& context, META_NS::Serialization::ClassPrimitive& value) const override
3018bf80f4bSopenharmony_ci    {
3028bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("MaterialImpl::%s %s", __func__, Name()->Get().c_str());
3038bf80f4bSopenharmony_ci
3048bf80f4bSopenharmony_ci        // This is not a shared material and therefore we will export it here.
3058bf80f4bSopenharmony_ci        return Fwd::Export(context, value);
3068bf80f4bSopenharmony_ci    }
3078bf80f4bSopenharmony_ci
3088bf80f4bSopenharmony_ci    bool Import(
3098bf80f4bSopenharmony_ci        META_NS::Serialization::IImportContext& context, const META_NS::Serialization::ClassPrimitive& value) override
3108bf80f4bSopenharmony_ci    {
3118bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Inputs)->Reset();
3128bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(CustomProperties)->Reset();
3138bf80f4bSopenharmony_ci
3148bf80f4bSopenharmony_ci        if (!Fwd::Import(context, value)) {
3158bf80f4bSopenharmony_ci            return false;
3168bf80f4bSopenharmony_ci        }
3178bf80f4bSopenharmony_ci
3188bf80f4bSopenharmony_ci        if (Inputs()) {
3198bf80f4bSopenharmony_ci            // Subscribe all texture infos.
3208bf80f4bSopenharmony_ci            for (auto i = 0; i < Inputs()->Size(); ++i) {
3218bf80f4bSopenharmony_ci                auto info = Inputs()->Get(i);
3228bf80f4bSopenharmony_ci
3238bf80f4bSopenharmony_ci                auto textureSlotIndex = info->GetTextureSlotIndex();
3248bf80f4bSopenharmony_ci                if (textureSlotIndex == ~0u) {
3258bf80f4bSopenharmony_ci                    textureSlotIndex = i;
3268bf80f4bSopenharmony_ci                }
3278bf80f4bSopenharmony_ci
3288bf80f4bSopenharmony_ci                info->SetTextureSlotIndex(textureSlotIndex);
3298bf80f4bSopenharmony_ci            }
3308bf80f4bSopenharmony_ci        }
3318bf80f4bSopenharmony_ci
3328bf80f4bSopenharmony_ci        return true;
3338bf80f4bSopenharmony_ci    }
3348bf80f4bSopenharmony_ci    */
3358bf80f4bSopenharmony_ci    SCENE_NS::ITextureInfo::Ptr GetTextureInfoByIndex(
3368bf80f4bSopenharmony_ci        uint32_t index, BASE_NS::vector<SCENE_NS::ITextureInfo::Ptr>& textures)
3378bf80f4bSopenharmony_ci    {
3388bf80f4bSopenharmony_ci        // First, look from current inputs.
3398bf80f4bSopenharmony_ci        auto existingInfo = GetTextureInfo(index);
3408bf80f4bSopenharmony_ci        if (existingInfo) {
3418bf80f4bSopenharmony_ci            // Found existing info, we absolutely want to re-use it.
3428bf80f4bSopenharmony_ci            // This is to keep e.g. property animations working (they bind to this exact object).
3438bf80f4bSopenharmony_ci            auto it = std::find(textures.begin(), textures.end(), existingInfo);
3448bf80f4bSopenharmony_ci            if (it == textures.end()) {
3458bf80f4bSopenharmony_ci                // Add this info to textures list.
3468bf80f4bSopenharmony_ci                textures.push_back(existingInfo);
3478bf80f4bSopenharmony_ci            }
3488bf80f4bSopenharmony_ci            return existingInfo;
3498bf80f4bSopenharmony_ci        }
3508bf80f4bSopenharmony_ci
3518bf80f4bSopenharmony_ci        for (auto& info : textures) {
3528bf80f4bSopenharmony_ci            if (info->GetTextureSlotIndex() == index) {
3538bf80f4bSopenharmony_ci                return info;
3548bf80f4bSopenharmony_ci            }
3558bf80f4bSopenharmony_ci        }
3568bf80f4bSopenharmony_ci
3578bf80f4bSopenharmony_ci        return {};
3588bf80f4bSopenharmony_ci    }
3598bf80f4bSopenharmony_ci
3608bf80f4bSopenharmony_ci    SCENE_NS::ITextureInfo::Ptr BindTextureSlot(const BASE_NS::string_view& propName, META_NS::IMetadata::Ptr& meta,
3618bf80f4bSopenharmony_ci        BASE_NS::vector<SCENE_NS::ITextureInfo::Ptr>& textures)
3628bf80f4bSopenharmony_ci    {
3638bf80f4bSopenharmony_ci        SCENE_NS::ITextureInfo::Ptr result;
3648bf80f4bSopenharmony_ci
3658bf80f4bSopenharmony_ci        // fork out the identifier
3668bf80f4bSopenharmony_ci        size_t ix = TEXTURE_PREFIX_SIZE;
3678bf80f4bSopenharmony_ci        ix = propName.find('.', ix + 1);
3688bf80f4bSopenharmony_ci        size_t textureSlotId = 0;
3698bf80f4bSopenharmony_ci
3708bf80f4bSopenharmony_ci        if (ix == BASE_NS::string_view::npos) {
3718bf80f4bSopenharmony_ci            return result;
3728bf80f4bSopenharmony_ci        } else {
3738bf80f4bSopenharmony_ci            // how cool is this
3748bf80f4bSopenharmony_ci            for (int ii = TEXTURE_PREFIX_SIZE; ii < ix; ii++) {
3758bf80f4bSopenharmony_ci                textureSlotId += (propName[ii] - '0') * pow(10, (ix - ii - 1)); // 10 exponent
3768bf80f4bSopenharmony_ci            }
3778bf80f4bSopenharmony_ci        }
3788bf80f4bSopenharmony_ci
3798bf80f4bSopenharmony_ci        auto textureSlotIndex = textureSlotId - 1;
3808bf80f4bSopenharmony_ci
3818bf80f4bSopenharmony_ci        bool applyPropertyToEcs = false;
3828bf80f4bSopenharmony_ci        if (textureSlotId) {
3838bf80f4bSopenharmony_ci            auto info = GetTextureInfoByIndex(textureSlotIndex, textures);
3848bf80f4bSopenharmony_ci            if (!info) {
3858bf80f4bSopenharmony_ci                info = GetObjectRegistry().Create<SCENE_NS::ITextureInfo>(SCENE_NS::ClassId::TextureInfo);
3868bf80f4bSopenharmony_ci                if (!info) {
3878bf80f4bSopenharmony_ci                    return {};
3888bf80f4bSopenharmony_ci                }
3898bf80f4bSopenharmony_ci
3908bf80f4bSopenharmony_ci                info->SetTextureSlotIndex(textureSlotIndex);
3918bf80f4bSopenharmony_ci                textures.push_back(info);
3928bf80f4bSopenharmony_ci            }
3938bf80f4bSopenharmony_ci
3948bf80f4bSopenharmony_ci            GET_HOLDER(info).SetSceneHolder(SceneHolder());
3958bf80f4bSopenharmony_ci
3968bf80f4bSopenharmony_ci            {
3978bf80f4bSopenharmony_ci                // Update name.
3988bf80f4bSopenharmony_ci                BASE_NS::string textureSlotName(propName.substr(ix + 1));
3998bf80f4bSopenharmony_ci                size_t dotIndex = textureSlotName.find('.');
4008bf80f4bSopenharmony_ci                if (dotIndex != BASE_NS::string_view::npos && dotIndex != 0) {
4018bf80f4bSopenharmony_ci                    textureSlotName = textureSlotName.substr(0, dotIndex);
4028bf80f4bSopenharmony_ci                }
4038bf80f4bSopenharmony_ci                if (GetValue(info->Name()) != textureSlotName) {
4048bf80f4bSopenharmony_ci                    SetValue(info->Name(), textureSlotName);
4058bf80f4bSopenharmony_ci                }
4068bf80f4bSopenharmony_ci            }
4078bf80f4bSopenharmony_ci
4088bf80f4bSopenharmony_ci            // progress one more dot
4098bf80f4bSopenharmony_ci            ix = propName.find('.', ix + 1);
4108bf80f4bSopenharmony_ci
4118bf80f4bSopenharmony_ci            BASE_NS::string propertyName(propName.substr(ix));
4128bf80f4bSopenharmony_ci            if (propertyName == ".factor") {
4138bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4>(GET_HOLDER(info), info->Factor(), meta, propName);
4148bf80f4bSopenharmony_ci            } else if (propertyName == ".transform.translation") {
4158bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec2>(GET_HOLDER(info), info->Translation(), meta, propName);
4168bf80f4bSopenharmony_ci            } else if (propertyName == ".transform.rotation") {
4178bf80f4bSopenharmony_ci                BindChanges<float>(GET_HOLDER(info), info->Rotation(), meta, propName);
4188bf80f4bSopenharmony_ci            } else if (propertyName == ".transform.scale") {
4198bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec2>(GET_HOLDER(info), info->Scale(), meta, propName);
4208bf80f4bSopenharmony_ci            } else if (propertyName == ".image") {
4218bf80f4bSopenharmony_ci                auto prop = meta->GetPropertyByName(propName);
4228bf80f4bSopenharmony_ci
4238bf80f4bSopenharmony_ci                // Here we will initialize the image property.
4248bf80f4bSopenharmony_ci                if (info->Image()->IsValueSet()) {
4258bf80f4bSopenharmony_ci                    // If the property value is set by the user, we will propagate it to ecs.
4268bf80f4bSopenharmony_ci                    ApplyTextureInfoImage(textureSlotIndex, *info);
4278bf80f4bSopenharmony_ci                } else {
4288bf80f4bSopenharmony_ci                    // If the property value is not set, we will fetch it from ecs.
4298bf80f4bSopenharmony_ci                    CheckImageHandle(textureSlotIndex, BASE_NS::weak_ptr<SCENE_NS::ITextureInfo>(info));
4308bf80f4bSopenharmony_ci                }
4318bf80f4bSopenharmony_ci
4328bf80f4bSopenharmony_ci                prop->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(
4338bf80f4bSopenharmony_ci                    [this, textureSlotIndex, w_info = Base::weak_ptr(info)]() {
4348bf80f4bSopenharmony_ci                        CheckImageHandle(textureSlotIndex, w_info);
4358bf80f4bSopenharmony_ci                    }));
4368bf80f4bSopenharmony_ci                GET_HOLDER(info).MarkRelated(info->Image(), prop);
4378bf80f4bSopenharmony_ci
4388bf80f4bSopenharmony_ci                SubscribeToTextureInfo(textureSlotIndex, info);
4398bf80f4bSopenharmony_ci            } else if (propertyName == ".sampler") {
4408bf80f4bSopenharmony_ci                GET_HOLDER(info).MarkRelated(info->Sampler(), meta->GetPropertyByName(propName));
4418bf80f4bSopenharmony_ci            }
4428bf80f4bSopenharmony_ci
4438bf80f4bSopenharmony_ci            result = info;
4448bf80f4bSopenharmony_ci        }
4458bf80f4bSopenharmony_ci
4468bf80f4bSopenharmony_ci        return result;
4478bf80f4bSopenharmony_ci    }
4488bf80f4bSopenharmony_ci
4498bf80f4bSopenharmony_ci    void CheckImageHandle(size_t arrayIx, BASE_NS::weak_ptr<SCENE_NS::ITextureInfo> w_info)
4508bf80f4bSopenharmony_ci    {
4518bf80f4bSopenharmony_ci        // Queue engine task
4528bf80f4bSopenharmony_ci        if (auto sceneHolder = SceneHolder()) {
4538bf80f4bSopenharmony_ci            sceneHolder->QueueEngineTask(
4548bf80f4bSopenharmony_ci                MakeTask(
4558bf80f4bSopenharmony_ci                    [entity = EcsObject()->GetEntity(), arrayIx, w_info](SceneHolder::Ptr sh) {
4568bf80f4bSopenharmony_ci                        // resolve entity
4578bf80f4bSopenharmony_ci                        CORE_NS::Entity image;
4588bf80f4bSopenharmony_ci                        BASE_NS::string name;
4598bf80f4bSopenharmony_ci                        RENDER_NS::GpuImageDesc imageDesc;
4608bf80f4bSopenharmony_ci                        RENDER_NS::RenderHandleReference handle;
4618bf80f4bSopenharmony_ci                        if (sh->GetImageEntity(entity, arrayIx, image)) {
4628bf80f4bSopenharmony_ci                            // get entity by uri
4638bf80f4bSopenharmony_ci                            sh->GetEntityUri(image, name);
4648bf80f4bSopenharmony_ci                            sh->GetImageHandle(image, handle, imageDesc);
4658bf80f4bSopenharmony_ci                        }
4668bf80f4bSopenharmony_ci                        SCENE_PLUGIN_VERBOSE_LOG("%s: resolved name: %s", __func__, name.c_str());
4678bf80f4bSopenharmony_ci                        // if we get something valid out of those
4688bf80f4bSopenharmony_ci                        // let the toolkit side check if we have a bitmap and its uri matches
4698bf80f4bSopenharmony_ci                        if (!name.empty()) {
4708bf80f4bSopenharmony_ci                            sh->QueueEngineTask(
4718bf80f4bSopenharmony_ci                                MakeTask(
4728bf80f4bSopenharmony_ci                                    [name](auto info, RENDER_NS::RenderHandleReference handle, auto size) {
4738bf80f4bSopenharmony_ci                                        if (auto bitmap = META_NS::GetValue(info->Image())) {
4748bf80f4bSopenharmony_ci                                            if (auto uriBitmap = interface_cast<SCENE_NS::IBitmap>(bitmap)) {
4758bf80f4bSopenharmony_ci                                                if (auto uri = META_NS::GetValue(uriBitmap->Uri());
4768bf80f4bSopenharmony_ci                                                    !uri.empty() && (uri == name)) {
4778bf80f4bSopenharmony_ci                                                    return false;
4788bf80f4bSopenharmony_ci                                                }
4798bf80f4bSopenharmony_ci                                            }
4808bf80f4bSopenharmony_ci                                        }
4818bf80f4bSopenharmony_ci                                        auto uriBitmap = META_NS::GetObjectRegistry().Create<SCENE_NS::IBitmap>(
4828bf80f4bSopenharmony_ci                                            SCENE_NS::ClassId::Bitmap);
4838bf80f4bSopenharmony_ci                                        META_NS::SetValue(uriBitmap->Uri(), name);
4848bf80f4bSopenharmony_ci                                        // TODO: should parse the renderhandle from the entity and set it to the bitmap
4858bf80f4bSopenharmony_ci                                        // also. as we "create" it from the ecs, so the image SHOULD already be loaded.
4868bf80f4bSopenharmony_ci                                        uriBitmap->SetRenderHandle(handle, size);
4878bf80f4bSopenharmony_ci                                        info->Image()->SetDefaultValue(uriBitmap, true);
4888bf80f4bSopenharmony_ci                                        return false;
4898bf80f4bSopenharmony_ci                                    },
4908bf80f4bSopenharmony_ci                                    w_info, handle, BASE_NS::Math::UVec2(imageDesc.width, imageDesc.height)),
4918bf80f4bSopenharmony_ci                                false);
4928bf80f4bSopenharmony_ci                        }
4938bf80f4bSopenharmony_ci                        return false;
4948bf80f4bSopenharmony_ci                    },
4958bf80f4bSopenharmony_ci                    sceneHolder),
4968bf80f4bSopenharmony_ci                false);
4978bf80f4bSopenharmony_ci        }
4988bf80f4bSopenharmony_ci    }
4998bf80f4bSopenharmony_ci
5008bf80f4bSopenharmony_ci    SCENE_NS::ITextureInfo::Ptr GetTextureInfo(size_t ix) const override
5018bf80f4bSopenharmony_ci    {
5028bf80f4bSopenharmony_ci        if (Inputs()) {
5038bf80f4bSopenharmony_ci            for (auto& info : Inputs()->GetValue()) {
5048bf80f4bSopenharmony_ci                if (info->GetTextureSlotIndex() == ix) {
5058bf80f4bSopenharmony_ci                    return info;
5068bf80f4bSopenharmony_ci                }
5078bf80f4bSopenharmony_ci            }
5088bf80f4bSopenharmony_ci        }
5098bf80f4bSopenharmony_ci
5108bf80f4bSopenharmony_ci        return SCENE_NS::ITextureInfo::Ptr {};
5118bf80f4bSopenharmony_ci    }
5128bf80f4bSopenharmony_ci
5138bf80f4bSopenharmony_ci    void UpdateInputProperties()
5148bf80f4bSopenharmony_ci    {
5158bf80f4bSopenharmony_ci        auto type = META_NS::GetValue(META_ACCESS_PROPERTY(Type));
5168bf80f4bSopenharmony_ci        bool includeDefaultMappings =
5178bf80f4bSopenharmony_ci            (type == SCENE_NS::IMaterial::METALLIC_ROUGHNESS || type == SCENE_NS::IMaterial::SPECULAR_GLOSSINESS ||
5188bf80f4bSopenharmony_ci                type == SCENE_NS::IMaterial::UNLIT || type == SCENE_NS::IMaterial::UNLIT_SHADOW_ALPHA);
5198bf80f4bSopenharmony_ci
5208bf80f4bSopenharmony_ci        // Base Color
5218bf80f4bSopenharmony_ci        if (auto meta =
5228bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::BASE_COLOR))) {
5238bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
5248bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
5258bf80f4bSopenharmony_ci                    meta->RemoveProperty(color);
5268bf80f4bSopenharmony_ci                }
5278bf80f4bSopenharmony_ci            } else {
5288bf80f4bSopenharmony_ci                auto c = META_NS::ConstructProperty<SCENE_NS::Color>(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR);
5298bf80f4bSopenharmony_ci                meta->AddProperty(c);
5308bf80f4bSopenharmony_ci            }
5318bf80f4bSopenharmony_ci        }
5328bf80f4bSopenharmony_ci
5338bf80f4bSopenharmony_ci        // Normal
5348bf80f4bSopenharmony_ci        if (auto meta =
5358bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::NORMAL))) {
5368bf80f4bSopenharmony_ci            if (auto scale = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE)) {
5378bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
5388bf80f4bSopenharmony_ci                    meta->RemoveProperty(scale);
5398bf80f4bSopenharmony_ci                }
5408bf80f4bSopenharmony_ci            } else {
5418bf80f4bSopenharmony_ci                auto s = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE);
5428bf80f4bSopenharmony_ci                meta->AddProperty(s);
5438bf80f4bSopenharmony_ci            }
5448bf80f4bSopenharmony_ci        }
5458bf80f4bSopenharmony_ci
5468bf80f4bSopenharmony_ci        //  Material
5478bf80f4bSopenharmony_ci        if (auto meta =
5488bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::MATERIAL))) {
5498bf80f4bSopenharmony_ci            // SCENE_NS::IMaterial::METALLIC_ROUGHNESS
5508bf80f4bSopenharmony_ci            if (auto roughness = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
5518bf80f4bSopenharmony_ci                if (type != SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5528bf80f4bSopenharmony_ci                    meta->RemoveProperty(roughness);
5538bf80f4bSopenharmony_ci                }
5548bf80f4bSopenharmony_ci            } else if (type == SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5558bf80f4bSopenharmony_ci                auto roughness = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS);
5568bf80f4bSopenharmony_ci                meta->AddProperty(roughness);
5578bf80f4bSopenharmony_ci            }
5588bf80f4bSopenharmony_ci            if (auto metallic = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_METALLIC)) {
5598bf80f4bSopenharmony_ci                if (type != SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5608bf80f4bSopenharmony_ci                    meta->RemoveProperty(metallic);
5618bf80f4bSopenharmony_ci                }
5628bf80f4bSopenharmony_ci            } else if (type == SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5638bf80f4bSopenharmony_ci                auto metallic = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_METALLIC);
5648bf80f4bSopenharmony_ci                meta->AddProperty(metallic);
5658bf80f4bSopenharmony_ci            }
5668bf80f4bSopenharmony_ci            if (auto reflectance = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_REFLECTANCE)) {
5678bf80f4bSopenharmony_ci                if (type != SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5688bf80f4bSopenharmony_ci                    meta->RemoveProperty(reflectance);
5698bf80f4bSopenharmony_ci                }
5708bf80f4bSopenharmony_ci            } else if (type == SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
5718bf80f4bSopenharmony_ci                auto reflectance = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_REFLECTANCE);
5728bf80f4bSopenharmony_ci                meta->AddProperty(reflectance);
5738bf80f4bSopenharmony_ci            }
5748bf80f4bSopenharmony_ci            // SCENE_NS::IMaterial::SPECULAR_GLOSSINESS
5758bf80f4bSopenharmony_ci            if (auto colorRGB = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
5768bf80f4bSopenharmony_ci                if (type != SCENE_NS::IMaterial::SPECULAR_GLOSSINESS) {
5778bf80f4bSopenharmony_ci                    meta->RemoveProperty(colorRGB);
5788bf80f4bSopenharmony_ci                }
5798bf80f4bSopenharmony_ci            } else if (type == SCENE_NS::IMaterial::SPECULAR_GLOSSINESS) {
5808bf80f4bSopenharmony_ci                auto colorRGB = META_NS::ConstructProperty<SCENE_NS::Color>(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR);
5818bf80f4bSopenharmony_ci                meta->AddProperty(colorRGB);
5828bf80f4bSopenharmony_ci            }
5838bf80f4bSopenharmony_ci            if (auto glossiness = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_GLOSSINESS)) {
5848bf80f4bSopenharmony_ci                if (type != SCENE_NS::IMaterial::SPECULAR_GLOSSINESS) {
5858bf80f4bSopenharmony_ci                    meta->RemoveProperty(glossiness);
5868bf80f4bSopenharmony_ci                }
5878bf80f4bSopenharmony_ci            } else if (type == SCENE_NS::IMaterial::SPECULAR_GLOSSINESS) {
5888bf80f4bSopenharmony_ci                auto glossiness = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_GLOSSINESS);
5898bf80f4bSopenharmony_ci                meta->AddProperty(glossiness);
5908bf80f4bSopenharmony_ci            }
5918bf80f4bSopenharmony_ci        }
5928bf80f4bSopenharmony_ci
5938bf80f4bSopenharmony_ci        // Emissive
5948bf80f4bSopenharmony_ci        if (auto meta =
5958bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::EMISSIVE))) {
5968bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
5978bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
5988bf80f4bSopenharmony_ci                    meta->RemoveProperty(color);
5998bf80f4bSopenharmony_ci                }
6008bf80f4bSopenharmony_ci            } else {
6018bf80f4bSopenharmony_ci                auto c = META_NS::ConstructProperty<SCENE_NS::Color>(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR);
6028bf80f4bSopenharmony_ci                meta->AddProperty(c);
6038bf80f4bSopenharmony_ci            }
6048bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY)) {
6058bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6068bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6078bf80f4bSopenharmony_ci                }
6088bf80f4bSopenharmony_ci            } else {
6098bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY);
6108bf80f4bSopenharmony_ci                meta->AddProperty(p);
6118bf80f4bSopenharmony_ci            }
6128bf80f4bSopenharmony_ci        }
6138bf80f4bSopenharmony_ci
6148bf80f4bSopenharmony_ci        // Ambient Occlusion
6158bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::AO))) {
6168bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH)) {
6178bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6188bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6198bf80f4bSopenharmony_ci                }
6208bf80f4bSopenharmony_ci            } else {
6218bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH);
6228bf80f4bSopenharmony_ci                meta->AddProperty(p);
6238bf80f4bSopenharmony_ci            }
6248bf80f4bSopenharmony_ci        }
6258bf80f4bSopenharmony_ci
6268bf80f4bSopenharmony_ci        // Clear Coat
6278bf80f4bSopenharmony_ci        if (auto meta =
6288bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT))) {
6298bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY)) {
6308bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6318bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6328bf80f4bSopenharmony_ci                }
6338bf80f4bSopenharmony_ci            } else {
6348bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY);
6358bf80f4bSopenharmony_ci                meta->AddProperty(p);
6368bf80f4bSopenharmony_ci            }
6378bf80f4bSopenharmony_ci        }
6388bf80f4bSopenharmony_ci
6398bf80f4bSopenharmony_ci        // Clear Coat Roughness
6408bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
6418bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT_ROUGHNESS))) {
6428bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
6438bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6448bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6458bf80f4bSopenharmony_ci                }
6468bf80f4bSopenharmony_ci            } else {
6478bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS);
6488bf80f4bSopenharmony_ci                meta->AddProperty(p);
6498bf80f4bSopenharmony_ci            }
6508bf80f4bSopenharmony_ci        }
6518bf80f4bSopenharmony_ci
6528bf80f4bSopenharmony_ci        // Clear Coat Normal
6538bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
6548bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT_NORMAL))) {
6558bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE)) {
6568bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6578bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6588bf80f4bSopenharmony_ci                }
6598bf80f4bSopenharmony_ci            } else {
6608bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE);
6618bf80f4bSopenharmony_ci                meta->AddProperty(p);
6628bf80f4bSopenharmony_ci            }
6638bf80f4bSopenharmony_ci        }
6648bf80f4bSopenharmony_ci
6658bf80f4bSopenharmony_ci        // Sheen
6668bf80f4bSopenharmony_ci        if (auto meta =
6678bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::SHEEN))) {
6688bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
6698bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6708bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6718bf80f4bSopenharmony_ci                }
6728bf80f4bSopenharmony_ci            } else {
6738bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<SCENE_NS::Color>(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR);
6748bf80f4bSopenharmony_ci                meta->AddProperty(p);
6758bf80f4bSopenharmony_ci            }
6768bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
6778bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6788bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6798bf80f4bSopenharmony_ci                }
6808bf80f4bSopenharmony_ci            } else {
6818bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS);
6828bf80f4bSopenharmony_ci                meta->AddProperty(p);
6838bf80f4bSopenharmony_ci            }
6848bf80f4bSopenharmony_ci        }
6858bf80f4bSopenharmony_ci
6868bf80f4bSopenharmony_ci        // TRANSMISSION
6878bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
6888bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::TRANSMISSION))) {
6898bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_TRANSMISSION)) {
6908bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
6918bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
6928bf80f4bSopenharmony_ci                }
6938bf80f4bSopenharmony_ci            } else {
6948bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_TRANSMISSION);
6958bf80f4bSopenharmony_ci                meta->AddProperty(p);
6968bf80f4bSopenharmony_ci            }
6978bf80f4bSopenharmony_ci        }
6988bf80f4bSopenharmony_ci
6998bf80f4bSopenharmony_ci        // Specular
7008bf80f4bSopenharmony_ci        if (auto meta =
7018bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::SPECULAR))) {
7028bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
7038bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
7048bf80f4bSopenharmony_ci                    meta->RemoveProperty(color);
7058bf80f4bSopenharmony_ci                }
7068bf80f4bSopenharmony_ci            } else {
7078bf80f4bSopenharmony_ci                auto c = META_NS::ConstructProperty<SCENE_NS::Color>(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR);
7088bf80f4bSopenharmony_ci                meta->AddProperty(c);
7098bf80f4bSopenharmony_ci            }
7108bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH)) {
7118bf80f4bSopenharmony_ci                if (!includeDefaultMappings) {
7128bf80f4bSopenharmony_ci                    meta->RemoveProperty(prop);
7138bf80f4bSopenharmony_ci                }
7148bf80f4bSopenharmony_ci            } else {
7158bf80f4bSopenharmony_ci                auto p = META_NS::ConstructProperty<float>(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH);
7168bf80f4bSopenharmony_ci                meta->AddProperty(p);
7178bf80f4bSopenharmony_ci            }
7188bf80f4bSopenharmony_ci        }
7198bf80f4bSopenharmony_ci    }
7208bf80f4bSopenharmony_ci
7218bf80f4bSopenharmony_ci    void BindInputProperties()
7228bf80f4bSopenharmony_ci    {
7238bf80f4bSopenharmony_ci        auto type = META_NS::GetValue(META_ACCESS_PROPERTY(Type));
7248bf80f4bSopenharmony_ci
7258bf80f4bSopenharmony_ci        // Base Color
7268bf80f4bSopenharmony_ci        if (auto meta =
7278bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::BASE_COLOR))) {
7288bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
7298bf80f4bSopenharmony_ci                ConvertBindChanges<SCENE_NS::Color, BASE_NS::Math::Vec4>(GET_HOLDER(meta),
7308bf80f4bSopenharmony_ci                    META_NS::Property<SCENE_NS::Color>(color), meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR);
7318bf80f4bSopenharmony_ci            }
7328bf80f4bSopenharmony_ci        }
7338bf80f4bSopenharmony_ci
7348bf80f4bSopenharmony_ci        // Normal
7358bf80f4bSopenharmony_ci        if (auto meta =
7368bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::NORMAL))) {
7378bf80f4bSopenharmony_ci            if (auto scale = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE)) {
7388bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(scale), meta,
7398bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 0);
7408bf80f4bSopenharmony_ci            }
7418bf80f4bSopenharmony_ci        }
7428bf80f4bSopenharmony_ci
7438bf80f4bSopenharmony_ci        //  Material
7448bf80f4bSopenharmony_ci        if (auto meta =
7458bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::MATERIAL))) {
7468bf80f4bSopenharmony_ci            // SCENE_NS::IMaterial::METALLIC_ROUGHNESS
7478bf80f4bSopenharmony_ci            if (type == SCENE_NS::IMaterial::METALLIC_ROUGHNESS) {
7488bf80f4bSopenharmony_ci                if (auto roughness = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
7498bf80f4bSopenharmony_ci                    BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(roughness),
7508bf80f4bSopenharmony_ci                        meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 1);
7518bf80f4bSopenharmony_ci                }
7528bf80f4bSopenharmony_ci                if (auto metallic = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_METALLIC)) {
7538bf80f4bSopenharmony_ci                    BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(metallic),
7548bf80f4bSopenharmony_ci                        meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 2); // 2 factor
7558bf80f4bSopenharmony_ci                }
7568bf80f4bSopenharmony_ci                if (auto reflectance = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_REFLECTANCE)) {
7578bf80f4bSopenharmony_ci                    BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(reflectance),
7588bf80f4bSopenharmony_ci                        meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 3); // 3 factor
7598bf80f4bSopenharmony_ci                }
7608bf80f4bSopenharmony_ci            }
7618bf80f4bSopenharmony_ci
7628bf80f4bSopenharmony_ci            // SCENE_NS::IMaterial::SPECULAR_GLOSSINESS
7638bf80f4bSopenharmony_ci            if (type == SCENE_NS::IMaterial::SPECULAR_GLOSSINESS) {
7648bf80f4bSopenharmony_ci                if (auto colorRGB = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
7658bf80f4bSopenharmony_ci                    BASE_NS::vector<size_t> slots = { 0, 0, 1, 1, 2, 2 };
7668bf80f4bSopenharmony_ci                    BindSlottedChanges<BASE_NS::Math::Vec4, SCENE_NS::Color>(GET_HOLDER(meta),
7678bf80f4bSopenharmony_ci                        META_NS::Property<SCENE_NS::Color>(colorRGB), meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR,
7688bf80f4bSopenharmony_ci                        slots);
7698bf80f4bSopenharmony_ci                }
7708bf80f4bSopenharmony_ci                if (auto glossiness = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_GLOSSINESS)) {
7718bf80f4bSopenharmony_ci                    BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(glossiness),
7728bf80f4bSopenharmony_ci                        meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 3);
7738bf80f4bSopenharmony_ci                }
7748bf80f4bSopenharmony_ci            }
7758bf80f4bSopenharmony_ci        }
7768bf80f4bSopenharmony_ci
7778bf80f4bSopenharmony_ci        // Emissive
7788bf80f4bSopenharmony_ci        if (auto meta =
7798bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::EMISSIVE))) {
7808bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
7818bf80f4bSopenharmony_ci                BASE_NS::vector<size_t> slots = { 0, 0, 1, 1, 2, 2 };
7828bf80f4bSopenharmony_ci                BindSlottedChanges<BASE_NS::Math::Vec4, SCENE_NS::Color>(GET_HOLDER(meta),
7838bf80f4bSopenharmony_ci                    META_NS::Property<SCENE_NS::Color>(color), meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR,
7848bf80f4bSopenharmony_ci                    slots);
7858bf80f4bSopenharmony_ci            }
7868bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY)) {
7878bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
7888bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 3);
7898bf80f4bSopenharmony_ci            }
7908bf80f4bSopenharmony_ci        }
7918bf80f4bSopenharmony_ci
7928bf80f4bSopenharmony_ci        // Ambient Occlusion
7938bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::AO))) {
7948bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH)) {
7958bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
7968bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 0);
7978bf80f4bSopenharmony_ci            }
7988bf80f4bSopenharmony_ci        }
7998bf80f4bSopenharmony_ci
8008bf80f4bSopenharmony_ci        // Clear Coat
8018bf80f4bSopenharmony_ci        if (auto meta =
8028bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT))) {
8038bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_INTENSITY)) {
8048bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8058bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 0);
8068bf80f4bSopenharmony_ci            }
8078bf80f4bSopenharmony_ci        }
8088bf80f4bSopenharmony_ci
8098bf80f4bSopenharmony_ci        // Clear Coat Roughness
8108bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
8118bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT_ROUGHNESS))) {
8128bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
8138bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8148bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 1);
8158bf80f4bSopenharmony_ci            }
8168bf80f4bSopenharmony_ci        }
8178bf80f4bSopenharmony_ci
8188bf80f4bSopenharmony_ci        // Clear Coat Normal
8198bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
8208bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::CLEARCOAT_NORMAL))) {
8218bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_NORMAL_SCALE)) {
8228bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8238bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 0);
8248bf80f4bSopenharmony_ci            }
8258bf80f4bSopenharmony_ci        }
8268bf80f4bSopenharmony_ci
8278bf80f4bSopenharmony_ci        // Sheen
8288bf80f4bSopenharmony_ci        if (auto meta =
8298bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::SHEEN))) {
8308bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
8318bf80f4bSopenharmony_ci                BASE_NS::vector<size_t> slots = { 0, 0, 1, 1, 2, 2 };
8328bf80f4bSopenharmony_ci                BindSlottedChanges<BASE_NS::Math::Vec4, SCENE_NS::Color>(GET_HOLDER(meta),
8338bf80f4bSopenharmony_ci                    META_NS::Property<SCENE_NS::Color>(prop), meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, slots);
8348bf80f4bSopenharmony_ci            }
8358bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_ROUGHNESS)) {
8368bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8378bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 3);
8388bf80f4bSopenharmony_ci            }
8398bf80f4bSopenharmony_ci        }
8408bf80f4bSopenharmony_ci
8418bf80f4bSopenharmony_ci        // TRANSMISSION
8428bf80f4bSopenharmony_ci        if (auto meta = interface_pointer_cast<META_NS::IMetadata>(
8438bf80f4bSopenharmony_ci                GetTextureInfo(CORE3D_NS::MaterialComponent::TRANSMISSION))) {
8448bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_TRANSMISSION)) {
8458bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8468bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 0);
8478bf80f4bSopenharmony_ci            }
8488bf80f4bSopenharmony_ci        }
8498bf80f4bSopenharmony_ci
8508bf80f4bSopenharmony_ci        // Specular
8518bf80f4bSopenharmony_ci        if (auto meta =
8528bf80f4bSopenharmony_ci                interface_pointer_cast<META_NS::IMetadata>(GetTextureInfo(CORE3D_NS::MaterialComponent::SPECULAR))) {
8538bf80f4bSopenharmony_ci            if (auto color = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_COLOR)) {
8548bf80f4bSopenharmony_ci                BASE_NS::vector<size_t> slots = { 0, 0, 1, 1, 2, 2 };
8558bf80f4bSopenharmony_ci                BindSlottedChanges<BASE_NS::Math::Vec4, SCENE_NS::Color>(GET_HOLDER(meta),
8568bf80f4bSopenharmony_ci                    META_NS::Property<SCENE_NS::Color>(color), meta, SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR,
8578bf80f4bSopenharmony_ci                    slots);
8588bf80f4bSopenharmony_ci            }
8598bf80f4bSopenharmony_ci            if (auto prop = meta->GetPropertyByName(SCENE_NS::IMaterial::MAPPED_INPUTS_STRENGTH)) {
8608bf80f4bSopenharmony_ci                BindChanges<BASE_NS::Math::Vec4, float>(GET_HOLDER(meta), META_NS::Property<float>(prop), meta,
8618bf80f4bSopenharmony_ci                    SCENE_NS::IMaterial::MAPPED_INPUTS_FACTOR, 3); // 3 factor
8628bf80f4bSopenharmony_ci            }
8638bf80f4bSopenharmony_ci        }
8648bf80f4bSopenharmony_ci    }
8658bf80f4bSopenharmony_ci
8668bf80f4bSopenharmony_ci    void OnTypeChanged()
8678bf80f4bSopenharmony_ci    {
8688bf80f4bSopenharmony_ci        UpdateInputProperties();
8698bf80f4bSopenharmony_ci        BindInputProperties();
8708bf80f4bSopenharmony_ci    }
8718bf80f4bSopenharmony_ci
8728bf80f4bSopenharmony_ci    // We intend to define the object only on demand
8738bf80f4bSopenharmony_ci    // If we have a previous object, we could try to preserve it
8748bf80f4bSopenharmony_ci    void UpdateCustomProperties()
8758bf80f4bSopenharmony_ci    {
8768bf80f4bSopenharmony_ci        // Store and remove old custom properties.
8778bf80f4bSopenharmony_ci        BASE_NS::vector<META_NS::IProperty::Ptr> oldCustomProperties;
8788bf80f4bSopenharmony_ci
8798bf80f4bSopenharmony_ci        auto properties = interface_pointer_cast<META_NS::IMetadata>(META_ACCESS_PROPERTY(CustomProperties)->GetValue());
8808bf80f4bSopenharmony_ci        if (properties) {
8818bf80f4bSopenharmony_ci            oldCustomProperties = properties->GetAllProperties();
8828bf80f4bSopenharmony_ci            properties->GetPropertyContainer()->RemoveAll();
8838bf80f4bSopenharmony_ci        }
8848bf80f4bSopenharmony_ci
8858bf80f4bSopenharmony_ci        // Find new custom properties.
8868bf80f4bSopenharmony_ci        BASE_NS::vector<META_NS::IProperty::Ptr> newCustomProperties;
8878bf80f4bSopenharmony_ci
8888bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
8898bf80f4bSopenharmony_ci        if (meta) {
8908bf80f4bSopenharmony_ci            // Collect all custom properties from ECS object.
8918bf80f4bSopenharmony_ci            auto metaProps = meta->GetAllProperties();
8928bf80f4bSopenharmony_ci            for (auto&& prop : metaProps) {
8938bf80f4bSopenharmony_ci                if (prop->GetName().compare(0, CUSTOM_PREFIX_SIZE, CUSTOM_PREFIX) == 0) {
8948bf80f4bSopenharmony_ci                    newCustomProperties.push_back(prop);
8958bf80f4bSopenharmony_ci                }
8968bf80f4bSopenharmony_ci            }
8978bf80f4bSopenharmony_ci        }
8988bf80f4bSopenharmony_ci
8998bf80f4bSopenharmony_ci        // If there are no custom properties, then reset.
9008bf80f4bSopenharmony_ci        if (newCustomProperties.empty()) {
9018bf80f4bSopenharmony_ci            META_ACCESS_PROPERTY(CustomProperties)->Reset();
9028bf80f4bSopenharmony_ci            return;
9038bf80f4bSopenharmony_ci        }
9048bf80f4bSopenharmony_ci
9058bf80f4bSopenharmony_ci        // Otherwise ensure that we have container for the custom properties.
9068bf80f4bSopenharmony_ci        if (!properties) {
9078bf80f4bSopenharmony_ci            properties = GetObjectRegistry().Create<META_NS::IMetadata>(SCENE_NS::ClassId::CustomPropertiesHolder);
9088bf80f4bSopenharmony_ci            META_ACCESS_PROPERTY(CustomProperties)->SetValue(interface_pointer_cast<META_NS::IObject>(properties));
9098bf80f4bSopenharmony_ci        }
9108bf80f4bSopenharmony_ci
9118bf80f4bSopenharmony_ci        GET_HOLDER(properties).SetSceneHolder(sceneHolder_.lock());
9128bf80f4bSopenharmony_ci
9138bf80f4bSopenharmony_ci        // Then create and bind all the custom properties.
9148bf80f4bSopenharmony_ci        for (auto& prop : newCustomProperties) {
9158bf80f4bSopenharmony_ci            // This is the new custom property.
9168bf80f4bSopenharmony_ci            META_NS::IProperty::Ptr property;
9178bf80f4bSopenharmony_ci
9188bf80f4bSopenharmony_ci            BASE_NS::string propertyName(prop->GetName().substr(CUSTOM_PREFIX_SIZE));
9198bf80f4bSopenharmony_ci
9208bf80f4bSopenharmony_ci            // Try to re-use the old custom property if we have one, it may have a meaningful value set.
9218bf80f4bSopenharmony_ci            for (auto& existing : oldCustomProperties) {
9228bf80f4bSopenharmony_ci                if (existing->GetName() == propertyName && existing->GetTypeId() == prop->GetTypeId()) {
9238bf80f4bSopenharmony_ci                    property = existing;
9248bf80f4bSopenharmony_ci                    break;
9258bf80f4bSopenharmony_ci                }
9268bf80f4bSopenharmony_ci            }
9278bf80f4bSopenharmony_ci
9288bf80f4bSopenharmony_ci            if (!property) {
9298bf80f4bSopenharmony_ci                // Clone property.
9308bf80f4bSopenharmony_ci                property = META_NS::DuplicatePropertyType(META_NS::GetObjectRegistry(), prop, propertyName);
9318bf80f4bSopenharmony_ci            }
9328bf80f4bSopenharmony_ci
9338bf80f4bSopenharmony_ci            // Add it to target.
9348bf80f4bSopenharmony_ci            properties->AddProperty(property);
9358bf80f4bSopenharmony_ci
9368bf80f4bSopenharmony_ci            // Bind it to ecs property.
9378bf80f4bSopenharmony_ci            BindMetaProperty(GET_HOLDER(properties), property, prop);
9388bf80f4bSopenharmony_ci        }
9398bf80f4bSopenharmony_ci    }
9408bf80f4bSopenharmony_ci
9418bf80f4bSopenharmony_ci    void UpdateInputs(bool forceRecursive = false, bool forceFullReset = true)
9428bf80f4bSopenharmony_ci    {
9438bf80f4bSopenharmony_ci        if (updatingInputs_ && !forceRecursive) {
9448bf80f4bSopenharmony_ci            return;
9458bf80f4bSopenharmony_ci        }
9468bf80f4bSopenharmony_ci
9478bf80f4bSopenharmony_ci        if (forceFullReset) {
9488bf80f4bSopenharmony_ci            updatingInputs_ = true;
9498bf80f4bSopenharmony_ci
9508bf80f4bSopenharmony_ci            propHandler_.Reset();
9518bf80f4bSopenharmony_ci            META_ACCESS_PROPERTY(Inputs)->Reset();
9528bf80f4bSopenharmony_ci            META_ACCESS_PROPERTY(CustomProperties)->Reset();
9538bf80f4bSopenharmony_ci
9548bf80f4bSopenharmony_ci            auto entity = EcsObject()->GetEntity();
9558bf80f4bSopenharmony_ci            auto ecs = EcsObject()->GetEcs();
9568bf80f4bSopenharmony_ci
9578bf80f4bSopenharmony_ci            // Reset the object
9588bf80f4bSopenharmony_ci            EcsObject()->BindObject(nullptr, entity);
9598bf80f4bSopenharmony_ci
9608bf80f4bSopenharmony_ci            auto scene = EcsScene();
9618bf80f4bSopenharmony_ci            auto ecsObject = EcsObject();
9628bf80f4bSopenharmony_ci
9638bf80f4bSopenharmony_ci            Initialize(
9648bf80f4bSopenharmony_ci                scene, ecsObject, {}, META_NS::GetValue(Path()), META_NS::GetValue(Name()), sceneHolder_, entity);
9658bf80f4bSopenharmony_ci
9668bf80f4bSopenharmony_ci            updatingInputs_ = false;
9678bf80f4bSopenharmony_ci        } else {
9688bf80f4bSopenharmony_ci            // This will potentially go wrong if the proxy properties contain set values
9698bf80f4bSopenharmony_ci            // The values previously set will replace the values from engine
9708bf80f4bSopenharmony_ci            if (UpdateAllInputProperties()) {
9718bf80f4bSopenharmony_ci                updatingInputs_ = true;
9728bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(Inputs)->Reset();
9738bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(CustomProperties)->Reset();
9748bf80f4bSopenharmony_ci                CompleteInitialization(META_NS::GetValue(Name()));
9758bf80f4bSopenharmony_ci                updatingInputs_ = false;
9768bf80f4bSopenharmony_ci            }
9778bf80f4bSopenharmony_ci        }
9788bf80f4bSopenharmony_ci    }
9798bf80f4bSopenharmony_ci
9808bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view MATERIAL_SHADER_NAME { "MaterialComponent.materialShader.shader" };
9818bf80f4bSopenharmony_ci    static constexpr BASE_NS::string_view DEPTH_SHADER_NAME { "MaterialComponent.depthShader.shader" };
9828bf80f4bSopenharmony_ci
9838bf80f4bSopenharmony_ci    SCENE_NS::ITextureInfo::Ptr FindTextureInfo(BASE_NS::string_view name)
9848bf80f4bSopenharmony_ci    {
9858bf80f4bSopenharmony_ci        if (META_ACCESS_PROPERTY(Inputs)) {
9868bf80f4bSopenharmony_ci            for (auto& info : Inputs()->GetValue()) {
9878bf80f4bSopenharmony_ci                if (META_NS::GetValue(info->Name()) == name) {
9888bf80f4bSopenharmony_ci                    return info;
9898bf80f4bSopenharmony_ci                }
9908bf80f4bSopenharmony_ci            }
9918bf80f4bSopenharmony_ci        }
9928bf80f4bSopenharmony_ci        return {};
9938bf80f4bSopenharmony_ci    }
9948bf80f4bSopenharmony_ci
9958bf80f4bSopenharmony_ci    void CopyTextureInfoProperties(SCENE_NS::ITextureInfo::Ptr from, SCENE_NS::ITextureInfo::Ptr to)
9968bf80f4bSopenharmony_ci    {
9978bf80f4bSopenharmony_ci        if (from->Factor()->IsValueSet()) {
9988bf80f4bSopenharmony_ci            to->Factor()->SetValue(from->Factor()->GetValue());
9998bf80f4bSopenharmony_ci        }
10008bf80f4bSopenharmony_ci
10018bf80f4bSopenharmony_ci        if (from->Rotation()->IsValueSet()) {
10028bf80f4bSopenharmony_ci            to->Rotation()->SetValue(from->Rotation()->GetValue());
10038bf80f4bSopenharmony_ci        }
10048bf80f4bSopenharmony_ci
10058bf80f4bSopenharmony_ci        if (from->Scale()->IsValueSet()) {
10068bf80f4bSopenharmony_ci            to->Scale()->SetValue(from->Scale()->GetValue());
10078bf80f4bSopenharmony_ci        }
10088bf80f4bSopenharmony_ci
10098bf80f4bSopenharmony_ci        if (from->Translation()->IsValueSet()) {
10108bf80f4bSopenharmony_ci            to->Translation()->SetValue(from->Translation()->GetValue());
10118bf80f4bSopenharmony_ci        }
10128bf80f4bSopenharmony_ci
10138bf80f4bSopenharmony_ci        // Sampler enumeration works now using enums, it should follow uri
10148bf80f4bSopenharmony_ci        // but uri information is not available from engine yet
10158bf80f4bSopenharmony_ci        if (from->Sampler()->IsValueSet()) {
10168bf80f4bSopenharmony_ci            to->Sampler()->SetValue(from->Sampler()->GetValue());
10178bf80f4bSopenharmony_ci        }
10188bf80f4bSopenharmony_ci
10198bf80f4bSopenharmony_ci        // image goes through uri implementation
10208bf80f4bSopenharmony_ci        if (auto data = META_NS::GetValue(from->Image())) {
10218bf80f4bSopenharmony_ci            to->Image()->SetValue(from->Image()->GetValue());
10228bf80f4bSopenharmony_ci        }
10238bf80f4bSopenharmony_ci    }
10248bf80f4bSopenharmony_ci
10258bf80f4bSopenharmony_ci    bool SynchronizeInputsFromMetadata()
10268bf80f4bSopenharmony_ci    {
10278bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
10288bf80f4bSopenharmony_ci        if (!meta) {
10298bf80f4bSopenharmony_ci            return false;
10308bf80f4bSopenharmony_ci        }
10318bf80f4bSopenharmony_ci        // Texture slots need to be bound before other properties
10328bf80f4bSopenharmony_ci	BASE_NS::vector<SCENE_NS::ITextureInfo::Ptr> textures;
10338bf80f4bSopenharmony_ci	auto prop =
10348bf80f4bSopenharmony_ci            meta->GetArrayPropertyByName<CORE3D_NS::MaterialComponent::TextureInfo>("MaterialComponent.textures");
10358bf80f4bSopenharmony_ci	// slot names (unsure-what-they-were-before-but-matches-core3d-enum)
10368bf80f4bSopenharmony_ci	const char* TextureIndexName[] = { "BASE_COLOR", "NORMAL", "MATERIAL", "EMISSIVE", "AO", "CLEARCOAT",
10378bf80f4bSopenharmony_ci	    "CLEARCOAT_ROUGHNESS", "CLEARCOAT_NORMAL", "SHEEN", "TRANSMISSION", "SPECULAR" };
10388bf80f4bSopenharmony_ci	auto v = prop->GetValue();
10398bf80f4bSopenharmony_ci	auto shp = SceneHolder();
10408bf80f4bSopenharmony_ci	for (auto t : v) {
10418bf80f4bSopenharmony_ci	    int textureSlotIndex = textures.size();
10428bf80f4bSopenharmony_ci	    // create wrapping things..
10438bf80f4bSopenharmony_ci	    auto info = GetTextureInfoByIndex(textureSlotIndex, textures);
10448bf80f4bSopenharmony_ci	    if (!info) {
10458bf80f4bSopenharmony_ci	        auto& obr = GetObjectRegistry();
10468bf80f4bSopenharmony_ci		auto params = obr.ConstructMetadata();
10478bf80f4bSopenharmony_ci		using IntfPtr = META_NS::SharedPtrIInterface;
10488bf80f4bSopenharmony_ci		params->AddProperty(META_NS::ConstructProperty<META_NS::IProperty::Ptr>(
10498bf80f4bSopenharmony_ci		    "textureInfoArray", nullptr, META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE));
10508bf80f4bSopenharmony_ci		params->AddProperty(META_NS::ConstructProperty<uint32_t>(
10518bf80f4bSopenharmony_ci		    "textureSlotIndex", 0, META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE));
10528bf80f4bSopenharmony_ci		params->AddProperty(META_NS::ConstructProperty<uintptr_t>(
10538bf80f4bSopenharmony_ci		    "sceneHolder", 0, META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE));
10548bf80f4bSopenharmony_ci
10558bf80f4bSopenharmony_ci		// yes this is ugly.
10568bf80f4bSopenharmony_ci		params->GetPropertyByName<uintptr_t>("sceneHolder")->SetValue((uintptr_t)&shp);
10578bf80f4bSopenharmony_ci		params->GetPropertyByName<IntfPtr>("textureInfoArray")
10588bf80f4bSopenharmony_ci		    ->SetValue(interface_pointer_cast<CORE_NS::IInterface>(prop.GetProperty()));
10598bf80f4bSopenharmony_ci		params->GetPropertyByName<uint32_t>("textureSlotIndex")->SetValue(textureSlotIndex);
10608bf80f4bSopenharmony_ci		info = obr.Create<SCENE_NS::ITextureInfo>(SCENE_NS::ClassId::TextureInfo, params);
10618bf80f4bSopenharmony_ci		if (!info) {
10628bf80f4bSopenharmony_ci		    return {};
10638bf80f4bSopenharmony_ci		}
10648bf80f4bSopenharmony_ci
10658bf80f4bSopenharmony_ci		info->SetTextureSlotIndex(textureSlotIndex);
10668bf80f4bSopenharmony_ci		textures.push_back(info);
10678bf80f4bSopenharmony_ci	    } else {
10688bf80f4bSopenharmony_ci	        textures.push_back(nullptr);
10698bf80f4bSopenharmony_ci	    }
10708bf80f4bSopenharmony_ci	}
10718bf80f4bSopenharmony_ci
10728bf80f4bSopenharmony_ci        BASE_NS::vector<SCENE_NS::ITextureInfo::Ptr> prevInputs;
10738bf80f4bSopenharmony_ci        if (META_ACCESS_PROPERTY(Inputs)) {
10748bf80f4bSopenharmony_ci            auto size = META_ACCESS_PROPERTY(Inputs)->GetSize();
10758bf80f4bSopenharmony_ci            for (size_t ii = 0; ii < size; ii++) {
10768bf80f4bSopenharmony_ci                prevInputs.push_back(META_ACCESS_PROPERTY(Inputs)->GetValueAt(ii));
10778bf80f4bSopenharmony_ci            }
10788bf80f4bSopenharmony_ci        }
10798bf80f4bSopenharmony_ci
10808bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Inputs)->Reset();
10818bf80f4bSopenharmony_ci
10828bf80f4bSopenharmony_ci        // Sort texture infos.
10838bf80f4bSopenharmony_ci        std::sort(textures.begin(), textures.end(), [](const auto& a, const auto& b) {
10848bf80f4bSopenharmony_ci            // Sort based on texture-slot index.
10858bf80f4bSopenharmony_ci            return a->GetTextureSlotIndex() < b->GetTextureSlotIndex();
10868bf80f4bSopenharmony_ci        });
10878bf80f4bSopenharmony_ci
10888bf80f4bSopenharmony_ci        // Assign to property.
10898bf80f4bSopenharmony_ci        Inputs()->SetValue(textures);
10908bf80f4bSopenharmony_ci
10918bf80f4bSopenharmony_ci        // Copy values from old inputs to new ones.
10928bf80f4bSopenharmony_ci        for (auto& from : prevInputs) {
10938bf80f4bSopenharmony_ci            if (auto to = FindTextureInfo(META_NS::GetValue(from->Name()))) {
10948bf80f4bSopenharmony_ci                CopyTextureInfoProperties(from, to);
10958bf80f4bSopenharmony_ci            }
10968bf80f4bSopenharmony_ci        }
10978bf80f4bSopenharmony_ci
10988bf80f4bSopenharmony_ci        return true;
10998bf80f4bSopenharmony_ci    }
11008bf80f4bSopenharmony_ci
11018bf80f4bSopenharmony_ci    // return true if something changes
11028bf80f4bSopenharmony_ci    bool UpdateAllInputProperties()
11038bf80f4bSopenharmony_ci    {
11048bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(EcsObject());
11058bf80f4bSopenharmony_ci        if (!meta) {
11068bf80f4bSopenharmony_ci            return false;
11078bf80f4bSopenharmony_ci        }
11088bf80f4bSopenharmony_ci
11098bf80f4bSopenharmony_ci        auto oldCount = meta->GetPropertyContainer()->GetSize();
11108bf80f4bSopenharmony_ci
11118bf80f4bSopenharmony_ci        // This updates all properties from ecs and detaches properties that do not exist any more.
11128bf80f4bSopenharmony_ci        EcsObject()->DefineTargetProperties(PropertyNameMask());
11138bf80f4bSopenharmony_ci
11148bf80f4bSopenharmony_ci        auto newCount = meta->GetPropertyContainer()->GetSize();
11158bf80f4bSopenharmony_ci
11168bf80f4bSopenharmony_ci        auto allProperties = meta->GetAllProperties();
11178bf80f4bSopenharmony_ci
11188bf80f4bSopenharmony_ci        // if we add or remove something these all cannot match
11198bf80f4bSopenharmony_ci        return !((newCount == oldCount) && (oldCount != meta->GetPropertyContainer()->GetSize()));
11208bf80f4bSopenharmony_ci    }
11218bf80f4bSopenharmony_ci
11228bf80f4bSopenharmony_ci    bool CompleteInitialization(const BASE_NS::string& path) override
11238bf80f4bSopenharmony_ci    {
11248bf80f4bSopenharmony_ci        if (!NodeImpl::CompleteInitialization(path)) {
11258bf80f4bSopenharmony_ci            return false;
11268bf80f4bSopenharmony_ci        }
11278bf80f4bSopenharmony_ci
11288bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
11298bf80f4bSopenharmony_ci        if (!meta) {
11308bf80f4bSopenharmony_ci            return false;
11318bf80f4bSopenharmony_ci        }
11328bf80f4bSopenharmony_ci
11338bf80f4bSopenharmony_ci
11348bf80f4bSopenharmony_ci        if (DepthShader()->GetValue()) {
11358bf80f4bSopenharmony_ci            SceneHolder()->SetShader(
11368bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER, DepthShader()->GetValue());
11378bf80f4bSopenharmony_ci        } else {
11388bf80f4bSopenharmony_ci            // Try to introspect depth shader from material.
11398bf80f4bSopenharmony_ci            auto shader = SceneHolder()->GetShader(EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER);
11408bf80f4bSopenharmony_ci            if (shader) {
11418bf80f4bSopenharmony_ci                DepthShader()->SetValue(shader);
11428bf80f4bSopenharmony_ci            }
11438bf80f4bSopenharmony_ci        }
11448bf80f4bSopenharmony_ci
11458bf80f4bSopenharmony_ci        if (DepthShaderState()->GetValue()) {
11468bf80f4bSopenharmony_ci            SceneHolder()->SetGraphicsState(
11478bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER, DepthShaderState()->GetValue());
11488bf80f4bSopenharmony_ci        } else {
11498bf80f4bSopenharmony_ci            // Try to introspect depth shader from material.
11508bf80f4bSopenharmony_ci            auto state =
11518bf80f4bSopenharmony_ci                SceneHolder()->GetGraphicsState(EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER);
11528bf80f4bSopenharmony_ci            if (state) {
11538bf80f4bSopenharmony_ci                DepthShaderState()->SetValue(state);
11548bf80f4bSopenharmony_ci            }
11558bf80f4bSopenharmony_ci        }
11568bf80f4bSopenharmony_ci
11578bf80f4bSopenharmony_ci        if (MaterialShader()->GetValue()) {
11588bf80f4bSopenharmony_ci            SceneHolder()->SetShader(
11598bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER, MaterialShader()->GetValue());
11608bf80f4bSopenharmony_ci        } else {
11618bf80f4bSopenharmony_ci            // Try to introspect material shader from material.
11628bf80f4bSopenharmony_ci            auto shader = SceneHolder()->GetShader(EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER);
11638bf80f4bSopenharmony_ci            if (shader) {
11648bf80f4bSopenharmony_ci                MaterialShader()->SetValue(shader);
11658bf80f4bSopenharmony_ci            }
11668bf80f4bSopenharmony_ci        }
11678bf80f4bSopenharmony_ci
11688bf80f4bSopenharmony_ci        if (MaterialShaderState()->GetValue()) {
11698bf80f4bSopenharmony_ci            SceneHolder()->SetGraphicsState(
11708bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER, MaterialShaderState()->GetValue());
11718bf80f4bSopenharmony_ci        } else {
11728bf80f4bSopenharmony_ci            // Try to introspect depth shader from material.
11738bf80f4bSopenharmony_ci            auto state =
11748bf80f4bSopenharmony_ci                SceneHolder()->GetGraphicsState(EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER);
11758bf80f4bSopenharmony_ci            if (state) {
11768bf80f4bSopenharmony_ci                MaterialShaderState()->SetValue(state);
11778bf80f4bSopenharmony_ci            }
11788bf80f4bSopenharmony_ci        }
11798bf80f4bSopenharmony_ci
11808bf80f4bSopenharmony_ci        // Shader may have changed, so update all properties.
11818bf80f4bSopenharmony_ci        UpdateAllInputProperties();
11828bf80f4bSopenharmony_ci
11838bf80f4bSopenharmony_ci        // Properties up-to-date, synchronize all inputs.
11848bf80f4bSopenharmony_ci        SynchronizeInputsFromMetadata();
11858bf80f4bSopenharmony_ci
11868bf80f4bSopenharmony_ci        propHandler_.NewHandler(nullptr, nullptr).Subscribe(META_ACCESS_PROPERTY(Type), [this]() { OnTypeChanged(); });
11878bf80f4bSopenharmony_ci
11888bf80f4bSopenharmony_ci        BindChanges(propHandler_, META_ACCESS_PROPERTY(Type), meta, "MaterialComponent.type");
11898bf80f4bSopenharmony_ci
11908bf80f4bSopenharmony_ci        // Shader will either come as an entity ref from the engine, or from serialized info. have a listener
11918bf80f4bSopenharmony_ci        // that attaches the new ecs object to entity if one appears
11928bf80f4bSopenharmony_ci        propHandler_.NewHandler(nullptr, nullptr).Subscribe(DepthShader(), [this]() {
11938bf80f4bSopenharmony_ci            SceneHolder()->SetShader(
11948bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER, DepthShader()->GetValue());
11958bf80f4bSopenharmony_ci            UpdateInputs();
11968bf80f4bSopenharmony_ci        });
11978bf80f4bSopenharmony_ci
11988bf80f4bSopenharmony_ci        propHandler_.NewHandler(nullptr, nullptr).Subscribe(MaterialShader(), [this]() {
11998bf80f4bSopenharmony_ci            // Material shader has changed.
12008bf80f4bSopenharmony_ci            SceneHolder()->SetShader(
12018bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER, MaterialShader()->GetValue());
12028bf80f4bSopenharmony_ci            UpdateInputs();
12038bf80f4bSopenharmony_ci        });
12048bf80f4bSopenharmony_ci
12058bf80f4bSopenharmony_ci        propHandler_.NewHandler(nullptr, nullptr).Subscribe(DepthShaderState(), [this]() {
12068bf80f4bSopenharmony_ci            SceneHolder()->SetGraphicsState(
12078bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::DEPTH_SHADER, DepthShaderState()->GetValue());
12088bf80f4bSopenharmony_ci        });
12098bf80f4bSopenharmony_ci
12108bf80f4bSopenharmony_ci        propHandler_.NewHandler(nullptr, nullptr).Subscribe(MaterialShaderState(), [this]() {
12118bf80f4bSopenharmony_ci            // Material shader has changed.
12128bf80f4bSopenharmony_ci            SceneHolder()->SetGraphicsState(
12138bf80f4bSopenharmony_ci                EcsObject()->GetEntity(), SceneHolder::ShaderType::MATERIAL_SHADER, MaterialShaderState()->GetValue());
12148bf80f4bSopenharmony_ci        });
12158bf80f4bSopenharmony_ci
12168bf80f4bSopenharmony_ci        propHandler_.MarkRelated(MaterialShader(), meta->GetPropertyByName("MaterialComponent.materialShader.shader"));
12178bf80f4bSopenharmony_ci        propHandler_.MarkRelated(DepthShader(), meta->GetPropertyByName("MaterialComponent.depthShader.shader"));
12188bf80f4bSopenharmony_ci        propHandler_.MarkRelated(
12198bf80f4bSopenharmony_ci            MaterialShaderState(), meta->GetPropertyByName("MaterialComponent.materialShader.graphicsState"));
12208bf80f4bSopenharmony_ci        propHandler_.MarkRelated(
12218bf80f4bSopenharmony_ci            DepthShaderState(), meta->GetPropertyByName("MaterialComponent.depthShader.graphicsState"));
12228bf80f4bSopenharmony_ci
12238bf80f4bSopenharmony_ci        // make sure that inputs are up to date
12248bf80f4bSopenharmony_ci        OnTypeChanged();
12258bf80f4bSopenharmony_ci
12268bf80f4bSopenharmony_ci        // Update custom properties.
12278bf80f4bSopenharmony_ci        UpdateCustomProperties();
12288bf80f4bSopenharmony_ci
12298bf80f4bSopenharmony_ci        BindChanges(propHandler_, META_ACCESS_PROPERTY(AlphaCutoff), meta, "MaterialComponent.alphaCutoff");
12308bf80f4bSopenharmony_ci        BindChanges(propHandler_, META_ACCESS_PROPERTY(LightingFlags), meta, "MaterialComponent.materialLightingFlags");
12318bf80f4bSopenharmony_ci        return true;
12328bf80f4bSopenharmony_ci    }
12338bf80f4bSopenharmony_ci
12348bf80f4bSopenharmony_ci    bool BuildChildren(SCENE_NS::INode::BuildBehavior) override
12358bf80f4bSopenharmony_ci    {
12368bf80f4bSopenharmony_ci        // in typical cases we should not have children
12378bf80f4bSopenharmony_ci        if (META_NS::GetValue(META_ACCESS_PROPERTY(Status)) == SCENE_NS::INode::NODE_STATUS_CONNECTED) {
12388bf80f4bSopenharmony_ci            SetStatus(SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
12398bf80f4bSopenharmony_ci            META_NS::Invoke<META_NS::IOnChanged>(OnBound());
12408bf80f4bSopenharmony_ci            bound_ = true;
12418bf80f4bSopenharmony_ci        }
12428bf80f4bSopenharmony_ci        return true;
12438bf80f4bSopenharmony_ci    }
12448bf80f4bSopenharmony_ci
12458bf80f4bSopenharmony_ci    void SetImage(SCENE_NS::IBitmap::Ptr bitmap, BASE_NS::string_view textureSlot) override
12468bf80f4bSopenharmony_ci    {
12478bf80f4bSopenharmony_ci        auto size = Inputs()->GetSize();
12488bf80f4bSopenharmony_ci        for (size_t ii = 0; ii < size; ii++) {
12498bf80f4bSopenharmony_ci            if (META_NS::GetValue(Inputs()->GetValueAt(ii)->Name()).compare(textureSlot) == 0) {
12508bf80f4bSopenharmony_ci                SetImage(bitmap, ii);
12518bf80f4bSopenharmony_ci                break;
12528bf80f4bSopenharmony_ci            }
12538bf80f4bSopenharmony_ci        }
12548bf80f4bSopenharmony_ci    }
12558bf80f4bSopenharmony_ci
12568bf80f4bSopenharmony_ci    void SetImage(SCENE_NS::IBitmap::Ptr bitmap, size_t index) override
12578bf80f4bSopenharmony_ci    {
12588bf80f4bSopenharmony_ci        if (bitmap) {
12598bf80f4bSopenharmony_ci            auto status = META_NS::GetValue(bitmap->Status());
12608bf80f4bSopenharmony_ci            if (status == SCENE_NS::IBitmap::BitmapStatus::COMPLETED) {
12618bf80f4bSopenharmony_ci                if (auto sceneHolder = SceneHolder()) {
12628bf80f4bSopenharmony_ci                    sceneHolder->QueueEngineTask(
12638bf80f4bSopenharmony_ci                        MakeTask(
12648bf80f4bSopenharmony_ci                            [bitmap, index, weakSelf = BASE_NS::weak_ptr(GetSelf())](auto sh) {
12658bf80f4bSopenharmony_ci                                CORE_NS::Entity imageEntity = sh->BindUIBitmap(bitmap, true);
12668bf80f4bSopenharmony_ci                                auto image = sh->GetEcs()->GetEntityManager().GetReferenceCounted(imageEntity);
12678bf80f4bSopenharmony_ci                                sh->SetTexture(index,
12688bf80f4bSopenharmony_ci                                    interface_pointer_cast<INodeEcsInterfacePrivate>(weakSelf)
12698bf80f4bSopenharmony_ci                                        ->EcsObject()
12708bf80f4bSopenharmony_ci                                        ->GetEntity(),
12718bf80f4bSopenharmony_ci                                    image);
12728bf80f4bSopenharmony_ci                                sh->QueueApplicationTask(MakeTask([bitmap, index, weakSelf]() {
12738bf80f4bSopenharmony_ci                                    if (auto me = interface_pointer_cast<SCENE_NS::IMaterial>(weakSelf)) {
12748bf80f4bSopenharmony_ci                                        if (auto input = me->Inputs()->GetValueAt(index)) {
12758bf80f4bSopenharmony_ci                                            input->Image()->SetValue(bitmap);
12768bf80f4bSopenharmony_ci                                        }
12778bf80f4bSopenharmony_ci                                    }
12788bf80f4bSopenharmony_ci                                    return false;
12798bf80f4bSopenharmony_ci                                }),
12808bf80f4bSopenharmony_ci                                    false);
12818bf80f4bSopenharmony_ci
12828bf80f4bSopenharmony_ci                                return false;
12838bf80f4bSopenharmony_ci                            },
12848bf80f4bSopenharmony_ci                            sceneHolder),
12858bf80f4bSopenharmony_ci                        false);
12868bf80f4bSopenharmony_ci                }
12878bf80f4bSopenharmony_ci
12888bf80f4bSopenharmony_ci            } else {
12898bf80f4bSopenharmony_ci                // should basically subscribe to dynamic content instead
12908bf80f4bSopenharmony_ci                // Give uri based loading a shot
12918bf80f4bSopenharmony_ci                if (auto input = Inputs()->GetValueAt(index)) {
12928bf80f4bSopenharmony_ci                    input->Image()->SetValue(bitmap);
12938bf80f4bSopenharmony_ci                }
12948bf80f4bSopenharmony_ci            }
12958bf80f4bSopenharmony_ci        } else { // reset existing image if there is one
12968bf80f4bSopenharmony_ci            if (auto sceneHolder = SceneHolder()) {
12978bf80f4bSopenharmony_ci                sceneHolder->QueueEngineTask(MakeTask(
12988bf80f4bSopenharmony_ci                                                 [entityId = EcsObject()->GetEntity().id](auto sh) {
12998bf80f4bSopenharmony_ci                                                     CORE_NS::Entity target { entityId };
13008bf80f4bSopenharmony_ci                                                     // The assumption is that using base color ix is correct thing to
13018bf80f4bSopenharmony_ci                                                     // do
13028bf80f4bSopenharmony_ci                                                     sh->SetTexture(
13038bf80f4bSopenharmony_ci                                                         CORE3D_NS::MaterialComponent::BASE_COLOR, target, {});
13048bf80f4bSopenharmony_ci
13058bf80f4bSopenharmony_ci                                                     return false;
13068bf80f4bSopenharmony_ci                                                 },
13078bf80f4bSopenharmony_ci                                                 sceneHolder),
13088bf80f4bSopenharmony_ci                    false);
13098bf80f4bSopenharmony_ci            }
13108bf80f4bSopenharmony_ci        }
13118bf80f4bSopenharmony_ci    }
13128bf80f4bSopenharmony_ci};
13138bf80f4bSopenharmony_ci} // namespace
13148bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE()
13158bf80f4bSopenharmony_ci
13168bf80f4bSopenharmony_civoid RegisterMaterialImpl()
13178bf80f4bSopenharmony_ci{
13188bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().RegisterObjectType<MaterialImpl>();
13198bf80f4bSopenharmony_ci}
13208bf80f4bSopenharmony_civoid UnregisterMaterialImpl()
13218bf80f4bSopenharmony_ci{
13228bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().UnregisterObjectType<MaterialImpl>();
13238bf80f4bSopenharmony_ci}
13248bf80f4bSopenharmony_ci
13258bf80f4bSopenharmony_ciSCENE_END_NAMESPACE()
1326