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