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
168bf80f4bSopenharmony_ci#include <algorithm>
178bf80f4bSopenharmony_ci#include <scene_plugin/api/material_uid.h>
188bf80f4bSopenharmony_ci#include <scene_plugin/interface/compatibility.h>
198bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_bitmap.h>
208bf80f4bSopenharmony_ci
218bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_scene.h>
228bf80f4bSopenharmony_ci#include <meta/api/engine/util.h>
238bf80f4bSopenharmony_ci#include <meta/api/property/property_event_handler.h>
248bf80f4bSopenharmony_ci
258bf80f4bSopenharmony_ci#include "intf_postprocess_private.h"
268bf80f4bSopenharmony_ci#include "PropertyHandlerArrayHolder.h"
278bf80f4bSopenharmony_ci#include "scene_holder.h"
288bf80f4bSopenharmony_ci
298bf80f4bSopenharmony_ci
308bf80f4bSopenharmony_ciBASE_BEGIN_NAMESPACE()
318bf80f4bSopenharmony_ci
328bf80f4bSopenharmony_ci// our vector does not have op==
338bf80f4bSopenharmony_citemplate<typename T>
348bf80f4bSopenharmony_cibool operator==(const BASE_NS::vector<T>& l, const BASE_NS::vector<T>& r)
358bf80f4bSopenharmony_ci{
368bf80f4bSopenharmony_ci    if (l.size() != r.size()) {
378bf80f4bSopenharmony_ci        return false;
388bf80f4bSopenharmony_ci    }
398bf80f4bSopenharmony_ci    auto it1 = l.begin();
408bf80f4bSopenharmony_ci    auto it2 = r.begin();
418bf80f4bSopenharmony_ci    for (; it1 != l.end(); ++it1, ++it2) {
428bf80f4bSopenharmony_ci        if constexpr (META_NS::HasEqualOperator_v<T>) {
438bf80f4bSopenharmony_ci            if (!(*it1 == *it2)) {
448bf80f4bSopenharmony_ci                return false;
458bf80f4bSopenharmony_ci            }
468bf80f4bSopenharmony_ci        } else {
478bf80f4bSopenharmony_ci            return false;
488bf80f4bSopenharmony_ci        }
498bf80f4bSopenharmony_ci    }
508bf80f4bSopenharmony_ci    return true;
518bf80f4bSopenharmony_ci}
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_citemplate<typename T>
548bf80f4bSopenharmony_cibool operator!=(const BASE_NS::vector<T>& l, const BASE_NS::vector<T>& r)
558bf80f4bSopenharmony_ci{
568bf80f4bSopenharmony_ci    return !(l == r);
578bf80f4bSopenharmony_ci}
588bf80f4bSopenharmony_ci
598bf80f4bSopenharmony_ciBASE_END_NAMESPACE()
608bf80f4bSopenharmony_ci
618bf80f4bSopenharmony_cibool HasChangedProperties(META_NS::IMetadata& meta);
628bf80f4bSopenharmony_ci
638bf80f4bSopenharmony_citemplate<class EcsType, class UiType>
648bf80f4bSopenharmony_cistruct StaticConverter {
658bf80f4bSopenharmony_ci    static inline EcsType ToEcs(SceneHolder& sceneHolder, const UiType& v)
668bf80f4bSopenharmony_ci    {
678bf80f4bSopenharmony_ci        return static_cast<EcsType>(v);
688bf80f4bSopenharmony_ci    }
698bf80f4bSopenharmony_ci    static inline UiType ToUi(SceneHolder& sceneHolder, const EcsType& v)
708bf80f4bSopenharmony_ci    {
718bf80f4bSopenharmony_ci        return static_cast<UiType>(v);
728bf80f4bSopenharmony_ci    }
738bf80f4bSopenharmony_ci};
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_cistruct ImageConverter {
768bf80f4bSopenharmony_ci    static inline CORE_NS::EntityReference ToEcs(SceneHolder& sceneHolder, const SCENE_NS::IBitmap::Ptr& v)
778bf80f4bSopenharmony_ci    {
788bf80f4bSopenharmony_ci        // Get ecs image handle from bitmap.
798bf80f4bSopenharmony_ci        if (v) {
808bf80f4bSopenharmony_ci	    if (auto rh = v->GetRenderHandle()) {
818bf80f4bSopenharmony_ci                auto uri = META_NS::GetValue(v->Uri());
828bf80f4bSopenharmony_ci		return sceneHolder.LoadImage(uri, rh);
838bf80f4bSopenharmony_ci	    } else {
848bf80f4bSopenharmony_ci		auto uri = META_NS::GetValue(v->Uri());
858bf80f4bSopenharmony_ci		if (!uri.empty()) {
868bf80f4bSopenharmony_ci                    return sceneHolder.LoadImage(uri);
878bf80f4bSopenharmony_ci		}
888bf80f4bSopenharmony_ci            }
898bf80f4bSopenharmony_ci        }
908bf80f4bSopenharmony_ci        return {};
918bf80f4bSopenharmony_ci    }
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_ci    static inline SCENE_NS::IBitmap::Ptr ToUi(SceneHolder& sceneHolder, const CORE_NS::EntityReference& v)
948bf80f4bSopenharmony_ci    {
958bf80f4bSopenharmony_ci        CORE_NS::Entity image;
968bf80f4bSopenharmony_ci        BASE_NS::string uri;
978bf80f4bSopenharmony_ci        if (sceneHolder.GetEntityUri(v, uri)) {
988bf80f4bSopenharmony_ci	    RENDER_NS::GpuImageDesc desc;
998bf80f4bSopenharmony_ci	    RENDER_NS::RenderHandleReference rh;
1008bf80f4bSopenharmony_ci            auto uriBitmap = META_NS::GetObjectRegistry().Create<SCENE_NS::IBitmap>(SCENE_NS::ClassId::Bitmap);
1018bf80f4bSopenharmony_ci                if (sceneHolder.GetImageHandle(v, rh, desc)) {
1028bf80f4bSopenharmony_ci                uriBitmap->SetRenderHandle(rh, { desc.width, desc.height });	        
1038bf80f4bSopenharmony_ci	    }
1048bf80f4bSopenharmony_ci            META_NS::SetValue(uriBitmap->Uri(), uri);
1058bf80f4bSopenharmony_ci            return uriBitmap;
1068bf80f4bSopenharmony_ci        }
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci        return {};
1098bf80f4bSopenharmony_ci    }
1108bf80f4bSopenharmony_ci};
1118bf80f4bSopenharmony_ci
1128bf80f4bSopenharmony_citemplate<class ObjectType>
1138bf80f4bSopenharmony_cistruct EntityConverter {
1148bf80f4bSopenharmony_ci    static inline CORE_NS::Entity ToEcs(SceneHolder& sceneHolder, const typename ObjectType::Ptr& v)
1158bf80f4bSopenharmony_ci    {
1168bf80f4bSopenharmony_ci        // Get ecs object to entity.
1178bf80f4bSopenharmony_ci        if (auto ecsObject = interface_cast<SCENE_NS::IEcsObject>(v)) {
1188bf80f4bSopenharmony_ci            return ecsObject->GetEntity();
1198bf80f4bSopenharmony_ci        }
1208bf80f4bSopenharmony_ci        if (auto ippp = interface_cast<IPostProcessPrivate>(v)) {
1218bf80f4bSopenharmony_ci            return ippp->GetEntity();
1228bf80f4bSopenharmony_ci        }
1238bf80f4bSopenharmony_ci        return {};
1248bf80f4bSopenharmony_ci    }
1258bf80f4bSopenharmony_ci
1268bf80f4bSopenharmony_ci    static inline typename ObjectType::Ptr ToUi(SceneHolder& sceneHolder, const CORE_NS::Entity& v)
1278bf80f4bSopenharmony_ci    {
1288bf80f4bSopenharmony_ci        return {};
1298bf80f4bSopenharmony_ci    }
1308bf80f4bSopenharmony_ci};
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_citemplate<class originalType>
1338bf80f4bSopenharmony_ciinline auto& GetValueRef(originalType& from, size_t slot)
1348bf80f4bSopenharmony_ci{
1358bf80f4bSopenharmony_ci    return from[slot];
1368bf80f4bSopenharmony_ci}
1378bf80f4bSopenharmony_ci
1388bf80f4bSopenharmony_citemplate<>
1398bf80f4bSopenharmony_ciinline auto& GetValueRef<SCENE_NS::Color>(SCENE_NS::Color& from, size_t slot)
1408bf80f4bSopenharmony_ci{
1418bf80f4bSopenharmony_ci    if (slot == 0) {
1428bf80f4bSopenharmony_ci        return from.x;
1438bf80f4bSopenharmony_ci    } else if (slot == 1) {
1448bf80f4bSopenharmony_ci        return from.y;
1458bf80f4bSopenharmony_ci    } else if (slot == 2) { // 2 slot index
1468bf80f4bSopenharmony_ci        return from.z;
1478bf80f4bSopenharmony_ci    }
1488bf80f4bSopenharmony_ci    return from.w;
1498bf80f4bSopenharmony_ci}
1508bf80f4bSopenharmony_ci
1518bf80f4bSopenharmony_citemplate<class originalType, class valueType>
1528bf80f4bSopenharmony_ciinline bool SetValueFromComponent(META_NS::Property<valueType> to,
1538bf80f4bSopenharmony_ci    const META_NS::Property<originalType>& from, size_t slot, bool setAsDefault = false)
1548bf80f4bSopenharmony_ci{
1558bf80f4bSopenharmony_ci    originalType fromValue = from->GetValue();
1568bf80f4bSopenharmony_ci
1578bf80f4bSopenharmony_ci    if (to->GetValue() != fromValue[slot]) {
1588bf80f4bSopenharmony_ci        if (setAsDefault) {
1598bf80f4bSopenharmony_ci            to->SetDefaultValue(fromValue[slot], true);
1608bf80f4bSopenharmony_ci        } else {
1618bf80f4bSopenharmony_ci            to->SetValue(fromValue[slot]);
1628bf80f4bSopenharmony_ci        }
1638bf80f4bSopenharmony_ci        return true;
1648bf80f4bSopenharmony_ci    }
1658bf80f4bSopenharmony_ci    return false;
1668bf80f4bSopenharmony_ci}
1678bf80f4bSopenharmony_ci
1688bf80f4bSopenharmony_citemplate<>
1698bf80f4bSopenharmony_ciinline bool SetValueFromComponent<SCENE_NS::Color, float>(META_NS::Property<float> to,
1708bf80f4bSopenharmony_ci    const META_NS::Property<SCENE_NS::Color>& from, size_t slot, bool setAsDefault)
1718bf80f4bSopenharmony_ci{
1728bf80f4bSopenharmony_ci    SCENE_NS::Color fromValue = from->GetValue();
1738bf80f4bSopenharmony_ci
1748bf80f4bSopenharmony_ci    if (slot == 0) {
1758bf80f4bSopenharmony_ci        if (to->GetValue() != fromValue.x) {
1768bf80f4bSopenharmony_ci            if (setAsDefault) {
1778bf80f4bSopenharmony_ci                to->SetDefaultValue(fromValue.x, true);
1788bf80f4bSopenharmony_ci            } else {
1798bf80f4bSopenharmony_ci                to->SetValue(fromValue.x);
1808bf80f4bSopenharmony_ci            }
1818bf80f4bSopenharmony_ci        }
1828bf80f4bSopenharmony_ci    } else if (slot == 1) {
1838bf80f4bSopenharmony_ci        if (to->GetValue() != fromValue.y) {
1848bf80f4bSopenharmony_ci            if (setAsDefault) {
1858bf80f4bSopenharmony_ci                to->SetDefaultValue(fromValue.y, true);
1868bf80f4bSopenharmony_ci            } else {
1878bf80f4bSopenharmony_ci                to->SetValue(fromValue.y);
1888bf80f4bSopenharmony_ci            }
1898bf80f4bSopenharmony_ci        }
1908bf80f4bSopenharmony_ci    } else if (slot == 2) {
1918bf80f4bSopenharmony_ci        if (to->GetValue() != fromValue.z) {
1928bf80f4bSopenharmony_ci            if (setAsDefault) {
1938bf80f4bSopenharmony_ci                to->SetDefaultValue(fromValue.z, true);
1948bf80f4bSopenharmony_ci            } else {
1958bf80f4bSopenharmony_ci                to->SetValue(fromValue.z);
1968bf80f4bSopenharmony_ci            }
1978bf80f4bSopenharmony_ci        }
1988bf80f4bSopenharmony_ci    } else if (slot == 3) {
1998bf80f4bSopenharmony_ci        if (to->GetValue() != fromValue.w) {
2008bf80f4bSopenharmony_ci            if (setAsDefault) {
2018bf80f4bSopenharmony_ci                to->SetDefaultValue(fromValue.w, true);
2028bf80f4bSopenharmony_ci            } else {
2038bf80f4bSopenharmony_ci                to->SetValue(fromValue.w);
2048bf80f4bSopenharmony_ci            }
2058bf80f4bSopenharmony_ci        }
2068bf80f4bSopenharmony_ci    } else {
2078bf80f4bSopenharmony_ci        return false;
2088bf80f4bSopenharmony_ci    }
2098bf80f4bSopenharmony_ci    return true;
2108bf80f4bSopenharmony_ci}
2118bf80f4bSopenharmony_ci
2128bf80f4bSopenharmony_ci// Bending the implementation a bit, implicit conversion from TimeSpan to Seconds in float
2138bf80f4bSopenharmony_citemplate<>
2148bf80f4bSopenharmony_ciinline bool SetValueFromComponent<float, META_NS::TimeSpan>(META_NS::Property<META_NS::TimeSpan> to,
2158bf80f4bSopenharmony_ci    const META_NS::Property<float>& from, size_t /*slot*/, bool setAsDefault)
2168bf80f4bSopenharmony_ci{
2178bf80f4bSopenharmony_ci    META_NS::TimeSpan value;
2188bf80f4bSopenharmony_ci    value.SetSeconds(from->GetValue());
2198bf80f4bSopenharmony_ci    if (setAsDefault) {
2208bf80f4bSopenharmony_ci        to->SetDefaultValue(value, true);
2218bf80f4bSopenharmony_ci    } else {
2228bf80f4bSopenharmony_ci        to->SetValue(value);
2238bf80f4bSopenharmony_ci    }
2248bf80f4bSopenharmony_ci    return true;
2258bf80f4bSopenharmony_ci}
2268bf80f4bSopenharmony_ci
2278bf80f4bSopenharmony_citemplate<class originalType, class valueType>
2288bf80f4bSopenharmony_ciinline bool SetValueToComponent(META_NS::Property<originalType> to,
2298bf80f4bSopenharmony_ci    const META_NS::Property<valueType>& from, size_t slot)
2308bf80f4bSopenharmony_ci{
2318bf80f4bSopenharmony_ci    valueType fromValue = from->GetValue();
2328bf80f4bSopenharmony_ci    originalType toValue = to->GetValue();
2338bf80f4bSopenharmony_ci
2348bf80f4bSopenharmony_ci    if (toValue[slot] != fromValue) {
2358bf80f4bSopenharmony_ci        toValue[slot] = fromValue;
2368bf80f4bSopenharmony_ci        to->SetValue(toValue);
2378bf80f4bSopenharmony_ci        return true;
2388bf80f4bSopenharmony_ci    }
2398bf80f4bSopenharmony_ci    return false;
2408bf80f4bSopenharmony_ci}
2418bf80f4bSopenharmony_ci
2428bf80f4bSopenharmony_ci// Bending the implementation a bit, implicit conversion from TimeSpan to Seconds in float
2438bf80f4bSopenharmony_citemplate<>
2448bf80f4bSopenharmony_ciinline bool SetValueToComponent<float, META_NS::TimeSpan>(META_NS::Property<float> to,
2458bf80f4bSopenharmony_ci    const META_NS::Property<META_NS::TimeSpan>& from, size_t /*slot*/)
2468bf80f4bSopenharmony_ci{
2478bf80f4bSopenharmony_ci    to->SetValue(from->GetValue().ToSecondsFloat());
2488bf80f4bSopenharmony_ci    return true;
2498bf80f4bSopenharmony_ci}
2508bf80f4bSopenharmony_ci
2518bf80f4bSopenharmony_citemplate<>
2528bf80f4bSopenharmony_ciinline bool SetValueToComponent<SCENE_NS::Color, float>(META_NS::Property<SCENE_NS::Color> to,
2538bf80f4bSopenharmony_ci    const META_NS::Property<float>& from, size_t slot)
2548bf80f4bSopenharmony_ci{
2558bf80f4bSopenharmony_ci    float fromValue = from->GetValue();
2568bf80f4bSopenharmony_ci    SCENE_NS::Color toValue = to->GetValue();
2578bf80f4bSopenharmony_ci
2588bf80f4bSopenharmony_ci    if (slot == 0) {
2598bf80f4bSopenharmony_ci        if (toValue.x != fromValue) {
2608bf80f4bSopenharmony_ci            toValue.x = fromValue;
2618bf80f4bSopenharmony_ci        }
2628bf80f4bSopenharmony_ci    } else if (slot == 1) {
2638bf80f4bSopenharmony_ci        if (toValue.y != fromValue) {
2648bf80f4bSopenharmony_ci            toValue.y = fromValue;
2658bf80f4bSopenharmony_ci        }
2668bf80f4bSopenharmony_ci    } else if (slot == 2) { // 2 slot index
2678bf80f4bSopenharmony_ci        if (toValue.z != fromValue) {
2688bf80f4bSopenharmony_ci            toValue.z = fromValue;
2698bf80f4bSopenharmony_ci        }
2708bf80f4bSopenharmony_ci    } else if (slot == 3) { // 3 slot index
2718bf80f4bSopenharmony_ci        if (toValue.w != fromValue) {
2728bf80f4bSopenharmony_ci            toValue.w = fromValue;
2738bf80f4bSopenharmony_ci        }
2748bf80f4bSopenharmony_ci    } else {
2758bf80f4bSopenharmony_ci        return false;
2768bf80f4bSopenharmony_ci    }
2778bf80f4bSopenharmony_ci
2788bf80f4bSopenharmony_ci    to->SetValue(toValue);
2798bf80f4bSopenharmony_ci    return true;
2808bf80f4bSopenharmony_ci}
2818bf80f4bSopenharmony_ci
2828bf80f4bSopenharmony_cienum PropertyBindingType { ONE_WAY_TO_ECS, ONE_WAY_TO_UI, TWO_WAY };
2838bf80f4bSopenharmony_ci
2848bf80f4bSopenharmony_citemplate<class valueType, class sourceType, class Conv = StaticConverter<sourceType, valueType>>
2858bf80f4bSopenharmony_ciinline bool BindPropChanges(PropertyHandlerArrayHolder& handler,
2868bf80f4bSopenharmony_ci    META_NS::Property<valueType> propertyInstance,
2878bf80f4bSopenharmony_ci    META_NS::Property<sourceType> prop, PropertyBindingType type = TWO_WAY)
2888bf80f4bSopenharmony_ci{
2898bf80f4bSopenharmony_ci    if (!prop || !propertyInstance) {
2908bf80f4bSopenharmony_ci        return false;
2918bf80f4bSopenharmony_ci    }
2928bf80f4bSopenharmony_ci
2938bf80f4bSopenharmony_ci    auto sceneHolder = handler.GetSceneHolder();
2948bf80f4bSopenharmony_ci    if (!sceneHolder) {
2958bf80f4bSopenharmony_ci        return false;
2968bf80f4bSopenharmony_ci    }
2978bf80f4bSopenharmony_ci
2988bf80f4bSopenharmony_ci    bool useEcsPropertyValue = handler.GetUseEcsDefaults();
2998bf80f4bSopenharmony_ci    if (propertyInstance->IsValueSet()) {
3008bf80f4bSopenharmony_ci        useEcsPropertyValue = false;
3018bf80f4bSopenharmony_ci    }
3028bf80f4bSopenharmony_ci
3038bf80f4bSopenharmony_ci    // If we don't have local value, initialize value from ECS>
3048bf80f4bSopenharmony_ci    if (useEcsPropertyValue) {
3058bf80f4bSopenharmony_ci        auto ecsValue = Conv::ToUi(*sceneHolder, prop->GetValue());
3068bf80f4bSopenharmony_ci        // try to keep our value intact if the engine default value is the same as ours, otherwise we should
3078bf80f4bSopenharmony_ci        // update our default
3088bf80f4bSopenharmony_ci        if (ecsValue != propertyInstance->GetValue()) {
3098bf80f4bSopenharmony_ci            // Set to default value.
3108bf80f4bSopenharmony_ci            propertyInstance->SetDefaultValue(ecsValue, true);
3118bf80f4bSopenharmony_ci        }
3128bf80f4bSopenharmony_ci    } else { // otherwise reflect our value to ecs directly
3138bf80f4bSopenharmony_ci        prop->SetValue(Conv::ToEcs(*sceneHolder, propertyInstance->GetValue()));
3148bf80f4bSopenharmony_ci    }
3158bf80f4bSopenharmony_ci    if (type == ONE_WAY_TO_ECS || type == TWO_WAY) {
3168bf80f4bSopenharmony_ci        // and reflect the changes from us to ecs from now on
3178bf80f4bSopenharmony_ci        handler.NewHandler(prop, propertyInstance)
3188bf80f4bSopenharmony_ci            .Subscribe(propertyInstance, META_NS::MakeCallback<META_NS::IOnChanged>(
3198bf80f4bSopenharmony_ci                                             [propertyInstance, sh = sceneHolder](const auto& prop) {
3208bf80f4bSopenharmony_ci                                                if (prop) {
3218bf80f4bSopenharmony_ci                                                    prop->SetValue(Conv::ToEcs(*sh, propertyInstance->GetValue()));
3228bf80f4bSopenharmony_ci                                                    //hack
3238bf80f4bSopenharmony_ci                                                    /*if (auto v = META_NS::GetEngineValueFromProperty(prop.GetProperty())) {
3248bf80f4bSopenharmony_ci                                                        v->Sync(META_NS::EngineSyncDirection::TO_ENGINE);
3258bf80f4bSopenharmony_ci                                                    }*/
3268bf80f4bSopenharmony_ci                                                }
3278bf80f4bSopenharmony_ci                                             },
3288bf80f4bSopenharmony_ci                                             prop));
3298bf80f4bSopenharmony_ci    }
3308bf80f4bSopenharmony_ci
3318bf80f4bSopenharmony_ci    if (type == ONE_WAY_TO_UI || type == TWO_WAY) {
3328bf80f4bSopenharmony_ci        //  EcsObject reports changes back only if they take place on ecs side, so this should not cause race
3338bf80f4bSopenharmony_ci        //  They anyway don't support bindings properly, so having the feedback channel this way
3348bf80f4bSopenharmony_ci        handler.NewHandler(nullptr, nullptr)
3358bf80f4bSopenharmony_ci            .Subscribe(prop, META_NS::MakeCallback<META_NS::IOnChanged>(
3368bf80f4bSopenharmony_ci                                 [propertyInstance, sh = sceneHolder](const auto& prop) {
3378bf80f4bSopenharmony_ci                                    if (prop) {
3388bf80f4bSopenharmony_ci                                        if (!propertyInstance->GetBind()) {
3398bf80f4bSopenharmony_ci                                            propertyInstance->SetValue(Conv::ToUi(*sh, prop->GetValue()));
3408bf80f4bSopenharmony_ci                                        }
3418bf80f4bSopenharmony_ci                                    }
3428bf80f4bSopenharmony_ci                                },
3438bf80f4bSopenharmony_ci                                prop));
3448bf80f4bSopenharmony_ci    }
3458bf80f4bSopenharmony_ci
3468bf80f4bSopenharmony_ci    return true;
3478bf80f4bSopenharmony_ci}
3488bf80f4bSopenharmony_ci
3498bf80f4bSopenharmony_citemplate<class valueType, class sourceType, class Conv = StaticConverter<BASE_NS::vector<sourceType>, BASE_NS::vector<valueType>>>
3508bf80f4bSopenharmony_ciinline bool BindPropChanges(PropertyHandlerArrayHolder& handler, META_NS::ArrayProperty<valueType> propertyInstance,
3518bf80f4bSopenharmony_ci    META_NS::ArrayProperty<sourceType> prop, PropertyBindingType type = TWO_WAY)
3528bf80f4bSopenharmony_ci{
3538bf80f4bSopenharmony_ci    if (!prop || !propertyInstance) {
3548bf80f4bSopenharmony_ci        return false;
3558bf80f4bSopenharmony_ci    }
3568bf80f4bSopenharmony_ci
3578bf80f4bSopenharmony_ci    auto sceneHolder = handler.GetSceneHolder();
3588bf80f4bSopenharmony_ci    if (!sceneHolder) {
3598bf80f4bSopenharmony_ci        return false;
3608bf80f4bSopenharmony_ci    }
3618bf80f4bSopenharmony_ci
3628bf80f4bSopenharmony_ci    bool useEcsPropertyValue = handler.GetUseEcsDefaults();
3638bf80f4bSopenharmony_ci    if (propertyInstance->IsValueSet()) {
3648bf80f4bSopenharmony_ci        useEcsPropertyValue = false;
3658bf80f4bSopenharmony_ci    }
3668bf80f4bSopenharmony_ci
3678bf80f4bSopenharmony_ci    // If we don't have local value, initialize value from ECS>
3688bf80f4bSopenharmony_ci    if (useEcsPropertyValue) {
3698bf80f4bSopenharmony_ci        auto ecsValue = Conv::ToUi(*sceneHolder, prop->GetValue());
3708bf80f4bSopenharmony_ci        // try to keep our value intact if the engine default value is the same as ours, otherwise we should
3718bf80f4bSopenharmony_ci        // update our default
3728bf80f4bSopenharmony_ci        if (ecsValue != propertyInstance->GetValue()) {
3738bf80f4bSopenharmony_ci            // Set to default value.
3748bf80f4bSopenharmony_ci            propertyInstance->SetDefaultValue(ecsValue, true);
3758bf80f4bSopenharmony_ci        }
3768bf80f4bSopenharmony_ci    } else { // otherwise reflect our value to ecs directly
3778bf80f4bSopenharmony_ci        prop->SetValue(Conv::ToEcs(*sceneHolder, propertyInstance->GetValue()));
3788bf80f4bSopenharmony_ci    }
3798bf80f4bSopenharmony_ci    if (type == ONE_WAY_TO_ECS || type == TWO_WAY) {
3808bf80f4bSopenharmony_ci        // and reflect the changes from us to ecs from now on
3818bf80f4bSopenharmony_ci        handler.NewHandler(prop, propertyInstance)
3828bf80f4bSopenharmony_ci            .Subscribe(
3838bf80f4bSopenharmony_ci                propertyInstance, META_NS::MakeCallback<META_NS::IOnChanged>(
3848bf80f4bSopenharmony_ci                                      [propertyInstance, sh = sceneHolder](const auto& prop) {
3858bf80f4bSopenharmony_ci                                          if (prop) {
3868bf80f4bSopenharmony_ci                                              prop->SetValue(Conv::ToEcs(*sh, propertyInstance->GetValue()));
3878bf80f4bSopenharmony_ci                                              // hack
3888bf80f4bSopenharmony_ci                                          }
3898bf80f4bSopenharmony_ci                                      },
3908bf80f4bSopenharmony_ci                                      prop));
3918bf80f4bSopenharmony_ci    }
3928bf80f4bSopenharmony_ci
3938bf80f4bSopenharmony_ci    if (type == ONE_WAY_TO_UI || type == TWO_WAY) {
3948bf80f4bSopenharmony_ci        //  EcsObject reports changes back only if they take place on ecs side, so this should not cause race
3958bf80f4bSopenharmony_ci        //  They anyway don't support bindings properly, so having the feedback channel this way
3968bf80f4bSopenharmony_ci        handler.NewHandler(nullptr, nullptr)
3978bf80f4bSopenharmony_ci            .Subscribe(prop, META_NS::MakeCallback<META_NS::IOnChanged>(
3988bf80f4bSopenharmony_ci                                 [propertyInstance, sh = sceneHolder](const auto& prop) {
3998bf80f4bSopenharmony_ci                                     if (prop) {
4008bf80f4bSopenharmony_ci                                         if (!propertyInstance->GetBind()) {
4018bf80f4bSopenharmony_ci                                             propertyInstance->SetValue(Conv::ToUi(*sh, prop->GetValue()));
4028bf80f4bSopenharmony_ci                                         }
4038bf80f4bSopenharmony_ci                                     }
4048bf80f4bSopenharmony_ci                                 },
4058bf80f4bSopenharmony_ci                                 prop));
4068bf80f4bSopenharmony_ci    }
4078bf80f4bSopenharmony_ci
4088bf80f4bSopenharmony_ci    return true;
4098bf80f4bSopenharmony_ci}
4108bf80f4bSopenharmony_ci
4118bf80f4bSopenharmony_citemplate<class valueType>
4128bf80f4bSopenharmony_ciinline bool BindChanges(PropertyHandlerArrayHolder& handler,
4138bf80f4bSopenharmony_ci    META_NS::Property<valueType> propertyInstance, META_NS::IMetadata::Ptr meta,
4148bf80f4bSopenharmony_ci    const BASE_NS::string_view name)
4158bf80f4bSopenharmony_ci{
4168bf80f4bSopenharmony_ci    if (!meta || !propertyInstance) {
4178bf80f4bSopenharmony_ci        return false;
4188bf80f4bSopenharmony_ci    }
4198bf80f4bSopenharmony_ci
4208bf80f4bSopenharmony_ci    if (auto prop = meta->GetPropertyByName<valueType>(name)) {
4218bf80f4bSopenharmony_ci        // check if the target is already a proxy
4228bf80f4bSopenharmony_ci        if (auto target = handler.GetTarget(prop)) {
4238bf80f4bSopenharmony_ci            // this could go wrong if the target and proxy are different, mapped types
4248bf80f4bSopenharmony_ci            if (META_NS::Property<valueType> typed { target }) {
4258bf80f4bSopenharmony_ci                prop = typed;
4268bf80f4bSopenharmony_ci            } else {
4278bf80f4bSopenharmony_ci                CORE_LOG_W("%s: could not match the types for %s", __func__, BASE_NS::string(name).c_str());
4288bf80f4bSopenharmony_ci            }
4298bf80f4bSopenharmony_ci        }
4308bf80f4bSopenharmony_ci        return BindPropChanges<valueType>(handler, propertyInstance, prop);
4318bf80f4bSopenharmony_ci    }
4328bf80f4bSopenharmony_ci
4338bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("%s: could not find '%s'", __func__, name.data());
4348bf80f4bSopenharmony_ci    return false;
4358bf80f4bSopenharmony_ci}
4368bf80f4bSopenharmony_ci
4378bf80f4bSopenharmony_citemplate<class valueType>
4388bf80f4bSopenharmony_ciinline bool BindChanges(PropertyHandlerArrayHolder& handler, META_NS::ArrayProperty<valueType> propertyInstance,
4398bf80f4bSopenharmony_ci    META_NS::IMetadata::Ptr meta, const BASE_NS::string_view name)
4408bf80f4bSopenharmony_ci{
4418bf80f4bSopenharmony_ci    if (!meta || !propertyInstance) {
4428bf80f4bSopenharmony_ci        return false;
4438bf80f4bSopenharmony_ci    }
4448bf80f4bSopenharmony_ci
4458bf80f4bSopenharmony_ci    if (auto prop = meta->GetArrayPropertyByName<valueType>(name)) {
4468bf80f4bSopenharmony_ci        // check if the target is already a proxy
4478bf80f4bSopenharmony_ci        if (auto target = handler.GetTarget(prop)) {
4488bf80f4bSopenharmony_ci            // this could go wrong if the target and proxy are different, mapped types
4498bf80f4bSopenharmony_ci            if (META_NS::ArrayProperty<valueType> typed { target }) {
4508bf80f4bSopenharmony_ci                prop = typed;
4518bf80f4bSopenharmony_ci            } else {
4528bf80f4bSopenharmony_ci                CORE_LOG_W("%s: could not match the types for %s", __func__, BASE_NS::string(name).c_str());
4538bf80f4bSopenharmony_ci            }
4548bf80f4bSopenharmony_ci        }
4558bf80f4bSopenharmony_ci        return BindPropChanges<valueType>(handler, propertyInstance, prop);
4568bf80f4bSopenharmony_ci    }
4578bf80f4bSopenharmony_ci
4588bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("%s: could not find '%s'", __func__, name.data());
4598bf80f4bSopenharmony_ci    return false;
4608bf80f4bSopenharmony_ci}
4618bf80f4bSopenharmony_ci
4628bf80f4bSopenharmony_citemplate<class originalType, class valueType>
4638bf80f4bSopenharmony_ciinline bool setComponentValues(META_NS::Property<originalType> to,
4648bf80f4bSopenharmony_ci    const META_NS::Property<valueType>& from, BASE_NS::vector<size_t> slots,
4658bf80f4bSopenharmony_ci    bool setAsDefault = false)
4668bf80f4bSopenharmony_ci{
4678bf80f4bSopenharmony_ci    bool changed { false };
4688bf80f4bSopenharmony_ci    valueType fromValue = from->GetValue();
4698bf80f4bSopenharmony_ci    originalType toValue = to->GetValue();
4708bf80f4bSopenharmony_ci
4718bf80f4bSopenharmony_ci    for (size_t ix = 1; ix < slots.size();) {
4728bf80f4bSopenharmony_ci        auto slot1 = slots[ix - 1];
4738bf80f4bSopenharmony_ci        auto slot2 = slots[ix];
4748bf80f4bSopenharmony_ci        auto& value = GetValueRef<originalType>(toValue, slot1);
4758bf80f4bSopenharmony_ci        auto& value2 = GetValueRef<valueType>(fromValue, slot2);
4768bf80f4bSopenharmony_ci        if (value != value2) {
4778bf80f4bSopenharmony_ci            if (value != value && value2 != value2) {
4788bf80f4bSopenharmony_ci                CORE_LOG_D("omitting changes on NaN");
4798bf80f4bSopenharmony_ci            } else {
4808bf80f4bSopenharmony_ci                changed = true;
4818bf80f4bSopenharmony_ci                value = value2;
4828bf80f4bSopenharmony_ci            }
4838bf80f4bSopenharmony_ci        }
4848bf80f4bSopenharmony_ci        ix += 2; // 2 index shift
4858bf80f4bSopenharmony_ci    }
4868bf80f4bSopenharmony_ci    if (changed) {
4878bf80f4bSopenharmony_ci        if (setAsDefault) {
4888bf80f4bSopenharmony_ci            to->SetDefaultValue(toValue, true);
4898bf80f4bSopenharmony_ci        } else {
4908bf80f4bSopenharmony_ci            to->SetValue(toValue);
4918bf80f4bSopenharmony_ci        }
4928bf80f4bSopenharmony_ci    }
4938bf80f4bSopenharmony_ci    return changed;
4948bf80f4bSopenharmony_ci}
4958bf80f4bSopenharmony_ci
4968bf80f4bSopenharmony_citemplate<class originalType, class valueType>
4978bf80f4bSopenharmony_ciinline bool BindSlottedChanges(PropertyHandlerArrayHolder& handler,
4988bf80f4bSopenharmony_ci    META_NS::Property<valueType> propertyInstance, META_NS::IMetadata::Ptr meta,
4998bf80f4bSopenharmony_ci    const BASE_NS::string_view name, BASE_NS::vector<size_t> slots)
5008bf80f4bSopenharmony_ci{
5018bf80f4bSopenharmony_ci    if (!meta || !propertyInstance) {
5028bf80f4bSopenharmony_ci        return false;
5038bf80f4bSopenharmony_ci    }
5048bf80f4bSopenharmony_ci
5058bf80f4bSopenharmony_ci    if (auto prop = meta->GetPropertyByName<originalType>(name)) {
5068bf80f4bSopenharmony_ci        // If we don't have local value, initialize value from ECS>
5078bf80f4bSopenharmony_ci        bool useEcsPropertyValue = handler.GetUseEcsDefaults();
5088bf80f4bSopenharmony_ci        if (propertyInstance->IsValueSet()) {
5098bf80f4bSopenharmony_ci            useEcsPropertyValue = false;
5108bf80f4bSopenharmony_ci        }
5118bf80f4bSopenharmony_ci
5128bf80f4bSopenharmony_ci        // If we don't have local value, initialize value from ECS
5138bf80f4bSopenharmony_ci        if (useEcsPropertyValue) {
5148bf80f4bSopenharmony_ci            // Set default value.
5158bf80f4bSopenharmony_ci            setComponentValues(propertyInstance, prop, slots, true);
5168bf80f4bSopenharmony_ci        } else { // otherwise reflect our value to ecs directly
5178bf80f4bSopenharmony_ci            setComponentValues(prop, propertyInstance, slots);
5188bf80f4bSopenharmony_ci        }
5198bf80f4bSopenharmony_ci        // and reflect the changes from us to ecs from now on
5208bf80f4bSopenharmony_ci        handler.NewHandler(prop, propertyInstance)
5218bf80f4bSopenharmony_ci            .Subscribe(propertyInstance, META_NS::MakeCallback<META_NS::IOnChanged>(
5228bf80f4bSopenharmony_ci                                             [propertyInstance, slots](const auto& prop) {
5238bf80f4bSopenharmony_ci                                                 if (prop) {
5248bf80f4bSopenharmony_ci                                                     setComponentValues(prop, propertyInstance, slots);
5258bf80f4bSopenharmony_ci                                                 }
5268bf80f4bSopenharmony_ci                                             },
5278bf80f4bSopenharmony_ci                                             prop));
5288bf80f4bSopenharmony_ci        handler.NewHandler(nullptr, nullptr)
5298bf80f4bSopenharmony_ci            .Subscribe(prop, META_NS::MakeCallback<META_NS::IOnChanged>(
5308bf80f4bSopenharmony_ci                                 [propertyInstance, slots](const auto& prop) {
5318bf80f4bSopenharmony_ci                                     if (prop) {
5328bf80f4bSopenharmony_ci                                         setComponentValues(propertyInstance, prop, slots);
5338bf80f4bSopenharmony_ci                                     }
5348bf80f4bSopenharmony_ci                                 },
5358bf80f4bSopenharmony_ci                                 prop));
5368bf80f4bSopenharmony_ci
5378bf80f4bSopenharmony_ci        return true;
5388bf80f4bSopenharmony_ci    }
5398bf80f4bSopenharmony_ci    CORE_LOG_W("%s: could not find '%s'", __func__, name.data());
5408bf80f4bSopenharmony_ci    return false;
5418bf80f4bSopenharmony_ci}
5428bf80f4bSopenharmony_ci
5438bf80f4bSopenharmony_citemplate<class valueType, class sourceType, class Conv = StaticConverter<sourceType, valueType>>
5448bf80f4bSopenharmony_ciinline bool ConvertBindChanges(PropertyHandlerArrayHolder& handler,
5458bf80f4bSopenharmony_ci    META_NS::Property<valueType> propertyInstance, META_NS::IMetadata::Ptr meta,
5468bf80f4bSopenharmony_ci    const BASE_NS::string_view name, PropertyBindingType type = TWO_WAY)
5478bf80f4bSopenharmony_ci{
5488bf80f4bSopenharmony_ci    if (!meta || !propertyInstance) {
5498bf80f4bSopenharmony_ci        return false;
5508bf80f4bSopenharmony_ci    }
5518bf80f4bSopenharmony_ci
5528bf80f4bSopenharmony_ci    if (auto prop = meta->GetPropertyByName<sourceType>(name)) {
5538bf80f4bSopenharmony_ci        return BindPropChanges<valueType, sourceType, Conv>(handler, propertyInstance, prop, type);
5548bf80f4bSopenharmony_ci    }
5558bf80f4bSopenharmony_ci
5568bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("%s: could not find '%s'", __func__, name.data());
5578bf80f4bSopenharmony_ci    return false;
5588bf80f4bSopenharmony_ci}
5598bf80f4bSopenharmony_ci
5608bf80f4bSopenharmony_ci
5618bf80f4bSopenharmony_citemplate<class valueType>
5628bf80f4bSopenharmony_ciinline bool BindIfCorrectType(
5638bf80f4bSopenharmony_ci    PropertyHandlerArrayHolder& handler, META_NS::IProperty::Ptr& clone, META_NS::IProperty::Ptr& prop)
5648bf80f4bSopenharmony_ci{
5658bf80f4bSopenharmony_ci    if (clone->IsCompatible(META_NS::UidFromType<valueType>())) {
5668bf80f4bSopenharmony_ci        auto typed = META_NS::Property<valueType>(clone);
5678bf80f4bSopenharmony_ci        BindPropChanges<valueType>(handler, typed, META_NS::Property<valueType>(prop));
5688bf80f4bSopenharmony_ci        return true;
5698bf80f4bSopenharmony_ci    }
5708bf80f4bSopenharmony_ci
5718bf80f4bSopenharmony_ci    return false;
5728bf80f4bSopenharmony_ci}
5738bf80f4bSopenharmony_ci
5748bf80f4bSopenharmony_citemplate<class originalType, class valueType>
5758bf80f4bSopenharmony_ciinline bool BindChanges(PropertyHandlerArrayHolder& handler,
5768bf80f4bSopenharmony_ci    META_NS::Property<valueType> propertyInstance, META_NS::IMetadata::Ptr meta,
5778bf80f4bSopenharmony_ci    const BASE_NS::string_view name, size_t slot)
5788bf80f4bSopenharmony_ci{
5798bf80f4bSopenharmony_ci    if (!meta || !propertyInstance) {
5808bf80f4bSopenharmony_ci        return false;
5818bf80f4bSopenharmony_ci    }
5828bf80f4bSopenharmony_ci
5838bf80f4bSopenharmony_ci    if (auto prop = meta->GetPropertyByName<originalType>(name)) {
5848bf80f4bSopenharmony_ci        // check if the target is already a proxy
5858bf80f4bSopenharmony_ci        if (auto target = handler.GetTarget(prop)) {
5868bf80f4bSopenharmony_ci            // this could go wrong if the target and proxy are different, mapped types
5878bf80f4bSopenharmony_ci            if (auto typed = META_NS::Property<originalType>(target)) {
5888bf80f4bSopenharmony_ci                prop = typed;
5898bf80f4bSopenharmony_ci            } else {
5908bf80f4bSopenharmony_ci                CORE_LOG_W("%s: could not match the types for %s", __func__, BASE_NS::string(name).c_str());
5918bf80f4bSopenharmony_ci            }
5928bf80f4bSopenharmony_ci        }
5938bf80f4bSopenharmony_ci
5948bf80f4bSopenharmony_ci        bool useEcsPropertyValue = handler.GetUseEcsDefaults();
5958bf80f4bSopenharmony_ci        if (propertyInstance->IsValueSet()) {
5968bf80f4bSopenharmony_ci            useEcsPropertyValue = false;
5978bf80f4bSopenharmony_ci        }
5988bf80f4bSopenharmony_ci
5998bf80f4bSopenharmony_ci        // If we don't have local value, initialize value from ECS
6008bf80f4bSopenharmony_ci        if (useEcsPropertyValue) {
6018bf80f4bSopenharmony_ci            // Set to default value
6028bf80f4bSopenharmony_ci            SetValueFromComponent(propertyInstance, prop, slot, true);
6038bf80f4bSopenharmony_ci        } else { // otherwise reflect our value to ecs directly
6048bf80f4bSopenharmony_ci            SetValueToComponent(prop, propertyInstance, slot);
6058bf80f4bSopenharmony_ci        }
6068bf80f4bSopenharmony_ci        // and reflect the changes from us to ecs from now on
6078bf80f4bSopenharmony_ci        handler.NewHandler(prop, propertyInstance)
6088bf80f4bSopenharmony_ci            .Subscribe(propertyInstance, META_NS::MakeCallback<META_NS::IOnChanged>(
6098bf80f4bSopenharmony_ci                                             [propertyInstance, slot](const auto& prop) {
6108bf80f4bSopenharmony_ci                                                 if (prop) {
6118bf80f4bSopenharmony_ci                                                     SetValueToComponent(prop, propertyInstance, slot);
6128bf80f4bSopenharmony_ci                                                 }
6138bf80f4bSopenharmony_ci                                             },
6148bf80f4bSopenharmony_ci                                             prop));
6158bf80f4bSopenharmony_ci        handler.NewHandler(nullptr, nullptr)
6168bf80f4bSopenharmony_ci            .Subscribe(prop, META_NS::MakeCallback<META_NS::IOnChanged>(
6178bf80f4bSopenharmony_ci                                 [propertyInstance, slot](const auto& prop) {
6188bf80f4bSopenharmony_ci                                     if (prop) {
6198bf80f4bSopenharmony_ci                                         SetValueFromComponent(propertyInstance, prop, slot);
6208bf80f4bSopenharmony_ci                                     }
6218bf80f4bSopenharmony_ci                                 },
6228bf80f4bSopenharmony_ci                                 prop));
6238bf80f4bSopenharmony_ci
6248bf80f4bSopenharmony_ci        return true;
6258bf80f4bSopenharmony_ci    }
6268bf80f4bSopenharmony_ci    CORE_LOG_W("%s: could not find '%s'", __func__, name.data());
6278bf80f4bSopenharmony_ci    return false;
6288bf80f4bSopenharmony_ci}
629