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 "NodeImpl.h" 168bf80f4bSopenharmony_ci 178bf80f4bSopenharmony_ci#include <meta/api/make_callback.h> 188bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h> 198bf80f4bSopenharmony_ci#include <meta/interface/intf_container.h> 208bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue.h> 218bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h> 228bf80f4bSopenharmony_ci#include <napi_api.h> 238bf80f4bSopenharmony_ci#include <scene_plugin/api/camera_uid.h> 248bf80f4bSopenharmony_ci#include <scene_plugin/api/light_uid.h> 258bf80f4bSopenharmony_ci#include <scene_plugin/api/node_uid.h> 268bf80f4bSopenharmony_ci#include <scene_plugin/api/scene.h> 278bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_node.h> 288bf80f4bSopenharmony_ci 298bf80f4bSopenharmony_ci#include "BaseObjectJS.h" 308bf80f4bSopenharmony_civoid NodeImpl::RegisterEnums(NapiApi::Object exports) 318bf80f4bSopenharmony_ci{ 328bf80f4bSopenharmony_ci napi_value v; 338bf80f4bSopenharmony_ci NapiApi::Object NodeType(exports.GetEnv()); 348bf80f4bSopenharmony_ci#define DECL_ENUM(enu, x) \ 358bf80f4bSopenharmony_ci { \ 368bf80f4bSopenharmony_ci napi_create_uint32(enu.GetEnv(), NodeImpl::NodeType::x, &v); \ 378bf80f4bSopenharmony_ci enu.Set(#x, v); \ 388bf80f4bSopenharmony_ci } 398bf80f4bSopenharmony_ci DECL_ENUM(NodeType, NODE); 408bf80f4bSopenharmony_ci DECL_ENUM(NodeType, GEOMETRY); 418bf80f4bSopenharmony_ci DECL_ENUM(NodeType, CAMERA); 428bf80f4bSopenharmony_ci DECL_ENUM(NodeType, LIGHT); 438bf80f4bSopenharmony_ci#undef DECL_ENUM 448bf80f4bSopenharmony_ci exports.Set("NodeType", NodeType); 458bf80f4bSopenharmony_ci} 468bf80f4bSopenharmony_ciNodeImpl::NodeImpl(NodeType type) : SceneResourceImpl(SceneResourceImpl::NODE), type_(type) 478bf80f4bSopenharmony_ci{ 488bf80f4bSopenharmony_ci LOG_F("NodeImpl ++"); 498bf80f4bSopenharmony_ci} 508bf80f4bSopenharmony_ciNodeImpl::~NodeImpl() 518bf80f4bSopenharmony_ci{ 528bf80f4bSopenharmony_ci LOG_F("NodeImpl --"); 538bf80f4bSopenharmony_ci} 548bf80f4bSopenharmony_ci 558bf80f4bSopenharmony_civoid* NodeImpl::GetInstanceImpl(uint32_t id) 568bf80f4bSopenharmony_ci{ 578bf80f4bSopenharmony_ci if (id == NodeImpl::ID) { 588bf80f4bSopenharmony_ci return this; 598bf80f4bSopenharmony_ci } 608bf80f4bSopenharmony_ci return SceneResourceImpl::GetInstanceImpl(id); 618bf80f4bSopenharmony_ci} 628bf80f4bSopenharmony_ci 638bf80f4bSopenharmony_civoid NodeImpl::GetPropertyDescs(BASE_NS::vector<napi_property_descriptor>& props) 648bf80f4bSopenharmony_ci{ 658bf80f4bSopenharmony_ci using namespace NapiApi; 668bf80f4bSopenharmony_ci // META_NS::IContainer; 678bf80f4bSopenharmony_ci 688bf80f4bSopenharmony_ci SceneResourceImpl::GetPropertyDescs(props); 698bf80f4bSopenharmony_ci 708bf80f4bSopenharmony_ci // node 718bf80f4bSopenharmony_ci 728bf80f4bSopenharmony_ci props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetPath>("path")); 738bf80f4bSopenharmony_ci props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetPosition, &NodeImpl::SetPosition>("position")); 748bf80f4bSopenharmony_ci props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetRotation, &NodeImpl::SetRotation>("rotation")); 758bf80f4bSopenharmony_ci props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetScale, &NodeImpl::SetScale>("scale")); 768bf80f4bSopenharmony_ci props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetParent>("parent")); 778bf80f4bSopenharmony_ci props.push_back(TROGetSetProperty<bool, NodeImpl, &NodeImpl::GetVisible, &NodeImpl::SetVisible>("visible")); 788bf80f4bSopenharmony_ci props.push_back(TROGetSetProperty<bool, NodeImpl, &NodeImpl::GetChildContainer, &NodeImpl::SetVisible>("children")); 798bf80f4bSopenharmony_ci props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetNodeType>("nodeType")); 808bf80f4bSopenharmony_ci props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetLayerMask>("layerMask")); 818bf80f4bSopenharmony_ci 828bf80f4bSopenharmony_ci // node methods 838bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::Dispose>("destroy")); 848bf80f4bSopenharmony_ci props.push_back( 858bf80f4bSopenharmony_ci MakeTROMethod<FunctionContext<BASE_NS::string>, NodeImpl, &NodeImpl::GetNodeByPath>("getNodeByPath")); 868bf80f4bSopenharmony_ci 878bf80f4bSopenharmony_ci // layermask methods. 888bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<uint32_t>, NodeImpl, &NodeImpl::GetLayerMaskEnabled>("getEnabled")); 898bf80f4bSopenharmony_ci props.push_back( 908bf80f4bSopenharmony_ci MakeTROMethod<FunctionContext<uint32_t, bool>, NodeImpl, &NodeImpl::SetLayerMaskEnabled>("setEnabled")); 918bf80f4bSopenharmony_ci 928bf80f4bSopenharmony_ci // container 938bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<Object>, NodeImpl, &NodeImpl::AppendChild>("append")); 948bf80f4bSopenharmony_ci props.push_back( 958bf80f4bSopenharmony_ci MakeTROMethod<FunctionContext<Object, Object>, NodeImpl, &NodeImpl::InsertChildAfter>("insertAfter")); 968bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<Object>, NodeImpl, &NodeImpl::RemoveChild>("remove")); 978bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<uint32_t>, NodeImpl, &NodeImpl::GetChild>("get")); 988bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::ClearChildren>("clear")); 998bf80f4bSopenharmony_ci props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::GetCount>("count")); 1008bf80f4bSopenharmony_ci} 1018bf80f4bSopenharmony_cinapi_value NodeImpl::Dispose(NapiApi::FunctionContext<>& ctx) 1028bf80f4bSopenharmony_ci{ 1038bf80f4bSopenharmony_ci // Dispose of the native object. (makes the js object invalid) 1048bf80f4bSopenharmony_ci posProxy_.reset(); 1058bf80f4bSopenharmony_ci sclProxy_.reset(); 1068bf80f4bSopenharmony_ci rotProxy_.reset(); 1078bf80f4bSopenharmony_ci if (TrueRootObject* instance = GetThisRootObject(ctx)) { 1088bf80f4bSopenharmony_ci instance->DisposeNative(); 1098bf80f4bSopenharmony_ci } 1108bf80f4bSopenharmony_ci scene_.Reset(); 1118bf80f4bSopenharmony_ci return ctx.GetUndefined(); 1128bf80f4bSopenharmony_ci} 1138bf80f4bSopenharmony_cinapi_value NodeImpl::GetLayerMaskEnabled(NapiApi::FunctionContext<uint32_t>& ctx) 1148bf80f4bSopenharmony_ci{ 1158bf80f4bSopenharmony_ci uint32_t bit = ctx.Arg<0>(); 1168bf80f4bSopenharmony_ci bool enabled = false; 1178bf80f4bSopenharmony_ci if (auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) { 1188bf80f4bSopenharmony_ci uint64_t mask = 1ull << bit; 1198bf80f4bSopenharmony_ci ExecSyncTask([node, mask, &enabled]() { 1208bf80f4bSopenharmony_ci enabled = node->LayerMask()->GetValue() & mask; 1218bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 1228bf80f4bSopenharmony_ci }); 1238bf80f4bSopenharmony_ci } 1248bf80f4bSopenharmony_ci return ctx.GetBoolean(enabled); 1258bf80f4bSopenharmony_ci} 1268bf80f4bSopenharmony_cinapi_value NodeImpl::SetLayerMaskEnabled(NapiApi::FunctionContext<uint32_t, bool>& ctx) 1278bf80f4bSopenharmony_ci{ 1288bf80f4bSopenharmony_ci uint32_t bit = ctx.Arg<0>(); 1298bf80f4bSopenharmony_ci bool enabled = ctx.Arg<1>(); 1308bf80f4bSopenharmony_ci if (auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) { 1318bf80f4bSopenharmony_ci uint64_t mask = 1ull << bit; 1328bf80f4bSopenharmony_ci ExecSyncTask([node, enabled, mask]() { 1338bf80f4bSopenharmony_ci if (enabled) { 1348bf80f4bSopenharmony_ci node->LayerMask()->SetValue(node->LayerMask()->GetValue() | mask); 1358bf80f4bSopenharmony_ci } else { 1368bf80f4bSopenharmony_ci node->LayerMask()->SetValue(node->LayerMask()->GetValue() & ~mask); 1378bf80f4bSopenharmony_ci } 1388bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 1398bf80f4bSopenharmony_ci }); 1408bf80f4bSopenharmony_ci } 1418bf80f4bSopenharmony_ci return ctx.GetUndefined(); 1428bf80f4bSopenharmony_ci} 1438bf80f4bSopenharmony_ci 1448bf80f4bSopenharmony_cinapi_value NodeImpl::GetNodeType(NapiApi::FunctionContext<>& ctx) 1458bf80f4bSopenharmony_ci{ 1468bf80f4bSopenharmony_ci uint32_t type = -1; // return -1 if the object does not exist anymore 1478bf80f4bSopenharmony_ci if (auto node = interface_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) { 1488bf80f4bSopenharmony_ci type = type_; 1498bf80f4bSopenharmony_ci } 1508bf80f4bSopenharmony_ci napi_value value; 1518bf80f4bSopenharmony_ci napi_status status = napi_create_uint32(ctx, type, &value); 1528bf80f4bSopenharmony_ci return value; 1538bf80f4bSopenharmony_ci} 1548bf80f4bSopenharmony_ci 1558bf80f4bSopenharmony_cinapi_value NodeImpl::GetLayerMask(NapiApi::FunctionContext<>& ctx) 1568bf80f4bSopenharmony_ci{ 1578bf80f4bSopenharmony_ci if (auto node = interface_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) { 1588bf80f4bSopenharmony_ci return ctx.This(); 1598bf80f4bSopenharmony_ci } 1608bf80f4bSopenharmony_ci return ctx.GetUndefined(); 1618bf80f4bSopenharmony_ci} 1628bf80f4bSopenharmony_ci 1638bf80f4bSopenharmony_cinapi_value NodeImpl::GetPath(NapiApi::FunctionContext<>& ctx) 1648bf80f4bSopenharmony_ci{ 1658bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 1668bf80f4bSopenharmony_ci BASE_NS::string path; 1678bf80f4bSopenharmony_ci if (node) { 1688bf80f4bSopenharmony_ci ExecSyncTask([node, &path]() { 1698bf80f4bSopenharmony_ci if (interface_cast<META_NS::IContainable>(node)->GetParent()) { 1708bf80f4bSopenharmony_ci path = node->Path()->GetValue(); 1718bf80f4bSopenharmony_ci } 1728bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 1738bf80f4bSopenharmony_ci }); 1748bf80f4bSopenharmony_ci } 1758bf80f4bSopenharmony_ci napi_value value; 1768bf80f4bSopenharmony_ci napi_status status = napi_create_string_utf8(ctx, path.c_str(), path.length(), &value); 1778bf80f4bSopenharmony_ci return value; 1788bf80f4bSopenharmony_ci} 1798bf80f4bSopenharmony_ci 1808bf80f4bSopenharmony_cinapi_value NodeImpl::GetVisible(NapiApi::FunctionContext<>& ctx) 1818bf80f4bSopenharmony_ci{ 1828bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 1838bf80f4bSopenharmony_ci bool visible = false; 1848bf80f4bSopenharmony_ci if (node) { 1858bf80f4bSopenharmony_ci ExecSyncTask([node, &visible]() { 1868bf80f4bSopenharmony_ci visible = node->Visible()->GetValue(); 1878bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 1888bf80f4bSopenharmony_ci }); 1898bf80f4bSopenharmony_ci } 1908bf80f4bSopenharmony_ci napi_value value; 1918bf80f4bSopenharmony_ci napi_status status = napi_get_boolean(ctx, visible, &value); 1928bf80f4bSopenharmony_ci return value; 1938bf80f4bSopenharmony_ci} 1948bf80f4bSopenharmony_civoid NodeImpl::SetVisible(NapiApi::FunctionContext<bool>& ctx) 1958bf80f4bSopenharmony_ci{ 1968bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 1978bf80f4bSopenharmony_ci if (node) { 1988bf80f4bSopenharmony_ci bool visible = ctx.Arg<0>(); 1998bf80f4bSopenharmony_ci ExecSyncTask([node, visible]() { 2008bf80f4bSopenharmony_ci node->Visible()->SetValue(visible); 2018bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 2028bf80f4bSopenharmony_ci }); 2038bf80f4bSopenharmony_ci } 2048bf80f4bSopenharmony_ci} 2058bf80f4bSopenharmony_ci 2068bf80f4bSopenharmony_cinapi_value NodeImpl::GetPosition(NapiApi::FunctionContext<>& ctx) 2078bf80f4bSopenharmony_ci{ 2088bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2098bf80f4bSopenharmony_ci if (!node) { 2108bf80f4bSopenharmony_ci return ctx.GetUndefined(); 2118bf80f4bSopenharmony_ci } 2128bf80f4bSopenharmony_ci if (posProxy_ == nullptr) { 2138bf80f4bSopenharmony_ci posProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Position()); 2148bf80f4bSopenharmony_ci } 2158bf80f4bSopenharmony_ci return posProxy_ ? posProxy_->Value() : NapiApi::Value<NapiApi::Object>(); 2168bf80f4bSopenharmony_ci} 2178bf80f4bSopenharmony_ci 2188bf80f4bSopenharmony_civoid NodeImpl::SetPosition(NapiApi::FunctionContext<NapiApi::Object>& ctx) 2198bf80f4bSopenharmony_ci{ 2208bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2218bf80f4bSopenharmony_ci if (!node) { 2228bf80f4bSopenharmony_ci return; 2238bf80f4bSopenharmony_ci } 2248bf80f4bSopenharmony_ci NapiApi::Object obj = ctx.Arg<0>(); 2258bf80f4bSopenharmony_ci if (posProxy_ == nullptr) { 2268bf80f4bSopenharmony_ci posProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Position()); 2278bf80f4bSopenharmony_ci } 2288bf80f4bSopenharmony_ci posProxy_->SetValue(obj); 2298bf80f4bSopenharmony_ci} 2308bf80f4bSopenharmony_ci 2318bf80f4bSopenharmony_cinapi_value NodeImpl::GetScale(NapiApi::FunctionContext<>& ctx) 2328bf80f4bSopenharmony_ci{ 2338bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2348bf80f4bSopenharmony_ci if (!node) { 2358bf80f4bSopenharmony_ci return ctx.GetUndefined(); 2368bf80f4bSopenharmony_ci } 2378bf80f4bSopenharmony_ci if (sclProxy_ == nullptr) { 2388bf80f4bSopenharmony_ci sclProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Scale()); 2398bf80f4bSopenharmony_ci } 2408bf80f4bSopenharmony_ci return sclProxy_ ? sclProxy_->Value() : NapiApi::Value<NapiApi::Object>(); 2418bf80f4bSopenharmony_ci} 2428bf80f4bSopenharmony_ci 2438bf80f4bSopenharmony_civoid NodeImpl::SetScale(NapiApi::FunctionContext<NapiApi::Object>& ctx) 2448bf80f4bSopenharmony_ci{ 2458bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2468bf80f4bSopenharmony_ci if (!node) { 2478bf80f4bSopenharmony_ci return; 2488bf80f4bSopenharmony_ci } 2498bf80f4bSopenharmony_ci NapiApi::Object obj = ctx.Arg<0>(); 2508bf80f4bSopenharmony_ci if (sclProxy_ == nullptr) { 2518bf80f4bSopenharmony_ci sclProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Scale()); 2528bf80f4bSopenharmony_ci } 2538bf80f4bSopenharmony_ci sclProxy_->SetValue(obj); 2548bf80f4bSopenharmony_ci} 2558bf80f4bSopenharmony_ci 2568bf80f4bSopenharmony_cinapi_value NodeImpl::GetRotation(NapiApi::FunctionContext<>& ctx) 2578bf80f4bSopenharmony_ci{ 2588bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2598bf80f4bSopenharmony_ci if (!node) { 2608bf80f4bSopenharmony_ci return ctx.GetUndefined(); 2618bf80f4bSopenharmony_ci } 2628bf80f4bSopenharmony_ci if (rotProxy_ == nullptr) { 2638bf80f4bSopenharmony_ci rotProxy_ = BASE_NS::make_unique<QuatProxy>(ctx, node->Rotation()); 2648bf80f4bSopenharmony_ci } 2658bf80f4bSopenharmony_ci return rotProxy_ ? rotProxy_->Value() : NapiApi::Value<NapiApi::Object>(); 2668bf80f4bSopenharmony_ci} 2678bf80f4bSopenharmony_ci 2688bf80f4bSopenharmony_civoid NodeImpl::SetRotation(NapiApi::FunctionContext<NapiApi::Object>& ctx) 2698bf80f4bSopenharmony_ci{ 2708bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2718bf80f4bSopenharmony_ci if (!node) { 2728bf80f4bSopenharmony_ci return; 2738bf80f4bSopenharmony_ci } 2748bf80f4bSopenharmony_ci NapiApi::Object obj = ctx.Arg<0>(); 2758bf80f4bSopenharmony_ci if (rotProxy_ == nullptr) { 2768bf80f4bSopenharmony_ci rotProxy_ = BASE_NS::make_unique<QuatProxy>(ctx, node->Rotation()); 2778bf80f4bSopenharmony_ci } 2788bf80f4bSopenharmony_ci rotProxy_->SetValue(obj); 2798bf80f4bSopenharmony_ci} 2808bf80f4bSopenharmony_ci 2818bf80f4bSopenharmony_cinapi_value NodeImpl::GetParent(NapiApi::FunctionContext<>& ctx) 2828bf80f4bSopenharmony_ci{ 2838bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 2848bf80f4bSopenharmony_ci if (!node) { 2858bf80f4bSopenharmony_ci return ctx.GetNull(); 2868bf80f4bSopenharmony_ci } 2878bf80f4bSopenharmony_ci META_NS::IObject::Ptr root; 2888bf80f4bSopenharmony_ci if (auto containable = interface_cast<META_NS::IContainable>(node)) { 2898bf80f4bSopenharmony_ci ExecSyncTask([containable, &root]() { 2908bf80f4bSopenharmony_ci root = interface_pointer_cast<META_NS::IObject>(containable->GetParent()); 2918bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 2928bf80f4bSopenharmony_ci }); 2938bf80f4bSopenharmony_ci } 2948bf80f4bSopenharmony_ci 2958bf80f4bSopenharmony_ci if (!root) { 2968bf80f4bSopenharmony_ci // no parent. 2978bf80f4bSopenharmony_ci return ctx.GetNull(); 2988bf80f4bSopenharmony_ci } 2998bf80f4bSopenharmony_ci 3008bf80f4bSopenharmony_ci if (auto cached = FetchJsObj(root)) { 3018bf80f4bSopenharmony_ci // always return the same js object. 3028bf80f4bSopenharmony_ci return cached; 3038bf80f4bSopenharmony_ci } 3048bf80f4bSopenharmony_ci if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) { 3058bf80f4bSopenharmony_ci CORE_LOG_F("INVALID SCENE!"); 3068bf80f4bSopenharmony_ci } 3078bf80f4bSopenharmony_ci 3088bf80f4bSopenharmony_ci // create new js object for the native node. 3098bf80f4bSopenharmony_ci NapiApi::Object argJS(ctx); 3108bf80f4bSopenharmony_ci napi_value args[] = { scene_.GetValue(), argJS }; 3118bf80f4bSopenharmony_ci 3128bf80f4bSopenharmony_ci return CreateFromNativeInstance(ctx, root, false /*these are owned by the scene*/, BASE_NS::countof(args), args); 3138bf80f4bSopenharmony_ci} 3148bf80f4bSopenharmony_ci 3158bf80f4bSopenharmony_cinapi_value NodeImpl::GetChildContainer(NapiApi::FunctionContext<>& ctx) 3168bf80f4bSopenharmony_ci{ 3178bf80f4bSopenharmony_ci // make sure the child list is up to date. 3188bf80f4bSopenharmony_ci auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx)); 3198bf80f4bSopenharmony_ci if (node) { 3208bf80f4bSopenharmony_ci ExecSyncTask([node]() { 3218bf80f4bSopenharmony_ci node->BuildChildren(SCENE_NS::INode::BuildBehavior::NODE_BUILD_ONLY_DIRECT_CHILDREN); 3228bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 3238bf80f4bSopenharmony_ci }); 3248bf80f4bSopenharmony_ci } 3258bf80f4bSopenharmony_ci 3268bf80f4bSopenharmony_ci // Node implements Container<Node> 3278bf80f4bSopenharmony_ci return ctx.This(); 3288bf80f4bSopenharmony_ci} 3298bf80f4bSopenharmony_ci 3308bf80f4bSopenharmony_ci// container implementation 3318bf80f4bSopenharmony_cibool SkipNode(SCENE_NS::INode::Ptr node) 3328bf80f4bSopenharmony_ci{ 3338bf80f4bSopenharmony_ci auto o = interface_cast<META_NS::IObject>(node); 3348bf80f4bSopenharmony_ci auto classid = o->GetClassId(); 3358bf80f4bSopenharmony_ci // white list of nodes that are actual nodes.. 3368bf80f4bSopenharmony_ci if ((classid == SCENE_NS::ClassId::Camera) || (classid == SCENE_NS::ClassId::Light) || 3378bf80f4bSopenharmony_ci (classid == SCENE_NS::ClassId::Node)) { 3388bf80f4bSopenharmony_ci return false; 3398bf80f4bSopenharmony_ci } 3408bf80f4bSopenharmony_ci return true; 3418bf80f4bSopenharmony_ci} 3428bf80f4bSopenharmony_cinapi_value NodeImpl::GetChild(NapiApi::FunctionContext<uint32_t>& ctx) 3438bf80f4bSopenharmony_ci{ 3448bf80f4bSopenharmony_ci uint32_t index = ctx.Arg<0>(); 3458bf80f4bSopenharmony_ci META_NS::IObject::Ptr child; 3468bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 3478bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 3488bf80f4bSopenharmony_ci ExecSyncTask([container, index, &child]() { 3498bf80f4bSopenharmony_ci auto data = container->GetAll<SCENE_NS::INode>(); 3508bf80f4bSopenharmony_ci int count = 0; 3518bf80f4bSopenharmony_ci for (auto d : data) { 3528bf80f4bSopenharmony_ci // Skip nodes that are not real "nodes" 3538bf80f4bSopenharmony_ci if (SkipNode(d)) { 3548bf80f4bSopenharmony_ci continue; 3558bf80f4bSopenharmony_ci } 3568bf80f4bSopenharmony_ci if (count == index) { 3578bf80f4bSopenharmony_ci child = interface_pointer_cast<META_NS::IObject>(d); 3588bf80f4bSopenharmony_ci break; 3598bf80f4bSopenharmony_ci } 3608bf80f4bSopenharmony_ci count++; 3618bf80f4bSopenharmony_ci } 3628bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 3638bf80f4bSopenharmony_ci }); 3648bf80f4bSopenharmony_ci } 3658bf80f4bSopenharmony_ci if (!child) { 3668bf80f4bSopenharmony_ci // return null 3678bf80f4bSopenharmony_ci napi_value value; 3688bf80f4bSopenharmony_ci napi_get_null(ctx, &value); 3698bf80f4bSopenharmony_ci return value; 3708bf80f4bSopenharmony_ci } 3718bf80f4bSopenharmony_ci auto cached = FetchJsObj(child); 3728bf80f4bSopenharmony_ci if (!cached) { 3738bf80f4bSopenharmony_ci // was not cached yet, so recreate. 3748bf80f4bSopenharmony_ci NapiApi::Object argJS(ctx); 3758bf80f4bSopenharmony_ci auto scn = scene_.GetObject(); 3768bf80f4bSopenharmony_ci if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) { 3778bf80f4bSopenharmony_ci CORE_LOG_F("INVALID SCENE!"); 3788bf80f4bSopenharmony_ci } 3798bf80f4bSopenharmony_ci 3808bf80f4bSopenharmony_ci napi_value args[] = { scene_.GetValue(), argJS }; 3818bf80f4bSopenharmony_ci 3828bf80f4bSopenharmony_ci cached = 3838bf80f4bSopenharmony_ci CreateFromNativeInstance(ctx, child, false /*these are owned by the scene*/, BASE_NS::countof(args), args); 3848bf80f4bSopenharmony_ci } 3858bf80f4bSopenharmony_ci return cached; 3868bf80f4bSopenharmony_ci} 3878bf80f4bSopenharmony_ci 3888bf80f4bSopenharmony_cinapi_value NodeImpl::GetCount(NapiApi::FunctionContext<>& ctx) 3898bf80f4bSopenharmony_ci{ 3908bf80f4bSopenharmony_ci uint32_t count = 0; 3918bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 3928bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 3938bf80f4bSopenharmony_ci ExecSyncTask([container, &count]() { 3948bf80f4bSopenharmony_ci auto data = container->GetAll<SCENE_NS::INode>(); 3958bf80f4bSopenharmony_ci for (auto d : data) { 3968bf80f4bSopenharmony_ci // Skip nodes that are not real "nodes" 3978bf80f4bSopenharmony_ci if (SkipNode(d)) { 3988bf80f4bSopenharmony_ci continue; 3998bf80f4bSopenharmony_ci } 4008bf80f4bSopenharmony_ci count++; 4018bf80f4bSopenharmony_ci } 4028bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 4038bf80f4bSopenharmony_ci }); 4048bf80f4bSopenharmony_ci } 4058bf80f4bSopenharmony_ci napi_value value; 4068bf80f4bSopenharmony_ci napi_status nstatus = napi_create_uint32(ctx, count, &value); 4078bf80f4bSopenharmony_ci return value; 4088bf80f4bSopenharmony_ci} 4098bf80f4bSopenharmony_cinapi_value NodeImpl::AppendChild(NapiApi::FunctionContext<NapiApi::Object>& ctx) 4108bf80f4bSopenharmony_ci{ 4118bf80f4bSopenharmony_ci NapiApi::Object childJS = ctx.Arg<0>(); 4128bf80f4bSopenharmony_ci if ((napi_value)childJS == nullptr) { 4138bf80f4bSopenharmony_ci // okay. Invalid arg error? 4148bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4158bf80f4bSopenharmony_ci } 4168bf80f4bSopenharmony_ci auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS); 4178bf80f4bSopenharmony_ci if (!childNode) { 4188bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4198bf80f4bSopenharmony_ci } 4208bf80f4bSopenharmony_ci 4218bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 4228bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 4238bf80f4bSopenharmony_ci ExecSyncTask([container, childNode]() { 4248bf80f4bSopenharmony_ci container->Add(childNode); 4258bf80f4bSopenharmony_ci childNode->Visible()->SetValue(true); 4268bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 4278bf80f4bSopenharmony_ci }); 4288bf80f4bSopenharmony_ci } 4298bf80f4bSopenharmony_ci 4308bf80f4bSopenharmony_ci // make the js object keep a weak ref again (scene keeps the native object alive) 4318bf80f4bSopenharmony_ci // (or move ownership back from SceneJS? and remove dispose hook?) 4328bf80f4bSopenharmony_ci if (auto tro = GetRootObject(ctx, childJS)) { 4338bf80f4bSopenharmony_ci if (auto native = tro->GetNativeObject()) { 4348bf80f4bSopenharmony_ci tro->SetNativeObject(nullptr, true); 4358bf80f4bSopenharmony_ci tro->SetNativeObject(native, false); 4368bf80f4bSopenharmony_ci native.reset(); 4378bf80f4bSopenharmony_ci } 4388bf80f4bSopenharmony_ci } 4398bf80f4bSopenharmony_ci 4408bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4418bf80f4bSopenharmony_ci} 4428bf80f4bSopenharmony_cinapi_value NodeImpl::InsertChildAfter(NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object>& ctx) 4438bf80f4bSopenharmony_ci{ 4448bf80f4bSopenharmony_ci NapiApi::Object childJS = ctx.Arg<0>(); 4458bf80f4bSopenharmony_ci NapiApi::Object siblingJS = ctx.Arg<1>(); 4468bf80f4bSopenharmony_ci 4478bf80f4bSopenharmony_ci if ((napi_value)childJS == nullptr) { 4488bf80f4bSopenharmony_ci // okay. Invalid arg error? 4498bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4508bf80f4bSopenharmony_ci } 4518bf80f4bSopenharmony_ci auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS); 4528bf80f4bSopenharmony_ci if (!childNode) { 4538bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4548bf80f4bSopenharmony_ci } 4558bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr siblingNode; 4568bf80f4bSopenharmony_ci if (siblingJS) { 4578bf80f4bSopenharmony_ci siblingNode = GetNativeMeta<SCENE_NS::INode>(siblingJS); 4588bf80f4bSopenharmony_ci } 4598bf80f4bSopenharmony_ci 4608bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 4618bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 4628bf80f4bSopenharmony_ci ExecSyncTask([container, childNode, siblingNode]() { 4638bf80f4bSopenharmony_ci if (siblingNode) { 4648bf80f4bSopenharmony_ci auto data = container->GetAll<SCENE_NS::INode>(); 4658bf80f4bSopenharmony_ci int64_t index = 0; 4668bf80f4bSopenharmony_ci for (auto d : data) { 4678bf80f4bSopenharmony_ci index++; 4688bf80f4bSopenharmony_ci if (d == siblingNode) { 4698bf80f4bSopenharmony_ci // insert "after" the hit 4708bf80f4bSopenharmony_ci container->Insert(index, childNode); 4718bf80f4bSopenharmony_ci childNode->Visible()->SetValue(true); 4728bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 4738bf80f4bSopenharmony_ci } 4748bf80f4bSopenharmony_ci } 4758bf80f4bSopenharmony_ci // did not find the sibling.. do nothing? add first? add last? 4768bf80f4bSopenharmony_ci // for now add last.. 4778bf80f4bSopenharmony_ci container->Add(childNode); 4788bf80f4bSopenharmony_ci childNode->Visible()->SetValue(true); 4798bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 4808bf80f4bSopenharmony_ci } 4818bf80f4bSopenharmony_ci // insert as first.. 4828bf80f4bSopenharmony_ci container->Insert(0, childNode); 4838bf80f4bSopenharmony_ci childNode->Visible()->SetValue(true); 4848bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 4858bf80f4bSopenharmony_ci }); 4868bf80f4bSopenharmony_ci } 4878bf80f4bSopenharmony_ci 4888bf80f4bSopenharmony_ci // make the js object keep a weak ref again (scene keeps the native object alive) 4898bf80f4bSopenharmony_ci // (or move ownership back from SceneJS? and remove dispose hook?) 4908bf80f4bSopenharmony_ci if (auto tro = GetRootObject(ctx, childJS)) { 4918bf80f4bSopenharmony_ci if (auto native = tro->GetNativeObject()) { 4928bf80f4bSopenharmony_ci tro->SetNativeObject(nullptr, true); 4938bf80f4bSopenharmony_ci tro->SetNativeObject(native, false); 4948bf80f4bSopenharmony_ci native.reset(); 4958bf80f4bSopenharmony_ci } 4968bf80f4bSopenharmony_ci } 4978bf80f4bSopenharmony_ci 4988bf80f4bSopenharmony_ci return ctx.GetUndefined(); 4998bf80f4bSopenharmony_ci} 5008bf80f4bSopenharmony_ci 5018bf80f4bSopenharmony_civoid NodeImpl::ResetNativeObj(NapiApi::FunctionContext<>& ctx, NapiApi::Object& obj) 5028bf80f4bSopenharmony_ci{ 5038bf80f4bSopenharmony_ci if (auto tro = GetRootObject(ctx, obj)) { 5048bf80f4bSopenharmony_ci if (auto native = tro->GetNativeObject()) { 5058bf80f4bSopenharmony_ci tro->SetNativeObject(nullptr, false); 5068bf80f4bSopenharmony_ci tro->SetNativeObject(native, true); 5078bf80f4bSopenharmony_ci native.reset(); 5088bf80f4bSopenharmony_ci } 5098bf80f4bSopenharmony_ci } 5108bf80f4bSopenharmony_ci} 5118bf80f4bSopenharmony_ci 5128bf80f4bSopenharmony_cinapi_value NodeImpl::RemoveChild(NapiApi::FunctionContext<NapiApi::Object>& ctx) 5138bf80f4bSopenharmony_ci{ 5148bf80f4bSopenharmony_ci // okay. just detach from parent. (make parent invalid) 5158bf80f4bSopenharmony_ci // and disable it. 5168bf80f4bSopenharmony_ci NapiApi::Object childJS = ctx.Arg<0>(); 5178bf80f4bSopenharmony_ci if ((napi_value)childJS == nullptr) { 5188bf80f4bSopenharmony_ci // okay. Invalid arg error? 5198bf80f4bSopenharmony_ci return ctx.GetUndefined(); 5208bf80f4bSopenharmony_ci } 5218bf80f4bSopenharmony_ci auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS); 5228bf80f4bSopenharmony_ci if (!childNode) { 5238bf80f4bSopenharmony_ci return ctx.GetUndefined(); 5248bf80f4bSopenharmony_ci } 5258bf80f4bSopenharmony_ci 5268bf80f4bSopenharmony_ci // make the js object keep a strong ref. 5278bf80f4bSopenharmony_ci // (or give SceneJS ownership? and add dispose hook?) 5288bf80f4bSopenharmony_ci if (auto tro = GetRootObject(ctx, childJS)) { 5298bf80f4bSopenharmony_ci if (auto native = tro->GetNativeObject()) { 5308bf80f4bSopenharmony_ci tro->SetNativeObject(nullptr, false); 5318bf80f4bSopenharmony_ci tro->SetNativeObject(native, true); 5328bf80f4bSopenharmony_ci native.reset(); 5338bf80f4bSopenharmony_ci } 5348bf80f4bSopenharmony_ci } 5358bf80f4bSopenharmony_ci 5368bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 5378bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 5388bf80f4bSopenharmony_ci ExecSyncTask([container, childNode]() { 5398bf80f4bSopenharmony_ci container->Remove(childNode); 5408bf80f4bSopenharmony_ci childNode->Visible()->SetValue(false); 5418bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 5428bf80f4bSopenharmony_ci }); 5438bf80f4bSopenharmony_ci } 5448bf80f4bSopenharmony_ci return ctx.GetUndefined(); 5458bf80f4bSopenharmony_ci} 5468bf80f4bSopenharmony_ci 5478bf80f4bSopenharmony_cinapi_value NodeImpl::ClearChildren(NapiApi::FunctionContext<>& ctx) 5488bf80f4bSopenharmony_ci{ 5498bf80f4bSopenharmony_ci auto metaobj = GetThisNativeObject(ctx); 5508bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::INode::Ptr> removedNodes; 5518bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(metaobj)) { 5528bf80f4bSopenharmony_ci ExecSyncTask([container, &removedNodes]() { 5538bf80f4bSopenharmony_ci auto tmp = container->GetAll(); 5548bf80f4bSopenharmony_ci for (auto t : tmp) { 5558bf80f4bSopenharmony_ci if (auto node = interface_pointer_cast<SCENE_NS::INode>(t)) { 5568bf80f4bSopenharmony_ci if (SkipNode(node)) { 5578bf80f4bSopenharmony_ci continue; 5588bf80f4bSopenharmony_ci } 5598bf80f4bSopenharmony_ci container->Remove(node); 5608bf80f4bSopenharmony_ci node->Visible()->SetValue(false); 5618bf80f4bSopenharmony_ci removedNodes.emplace_back(BASE_NS::move(node)); 5628bf80f4bSopenharmony_ci } 5638bf80f4bSopenharmony_ci } 5648bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 5658bf80f4bSopenharmony_ci }); 5668bf80f4bSopenharmony_ci for (auto node : removedNodes) { 5678bf80f4bSopenharmony_ci if (auto cached = FetchJsObj(node)) { 5688bf80f4bSopenharmony_ci ResetNativeObj(ctx, cached); 5698bf80f4bSopenharmony_ci } 5708bf80f4bSopenharmony_ci } 5718bf80f4bSopenharmony_ci } 5728bf80f4bSopenharmony_ci return ctx.GetUndefined(); 5738bf80f4bSopenharmony_ci} 5748bf80f4bSopenharmony_ci 5758bf80f4bSopenharmony_ciSCENE_NS::INode::Ptr recurse_children(const SCENE_NS::INode::Ptr startNode, BASE_NS::string_view path) 5768bf80f4bSopenharmony_ci{ 5778bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr node = startNode; 5788bf80f4bSopenharmony_ci while (node != nullptr) { 5798bf80f4bSopenharmony_ci node->BuildChildren(SCENE_NS::INode::BuildBehavior::NODE_BUILD_ONLY_DIRECT_CHILDREN); 5808bf80f4bSopenharmony_ci // see if 5818bf80f4bSopenharmony_ci if (auto container = interface_cast<META_NS::IContainer>(node)) { 5828bf80f4bSopenharmony_ci auto pos = path.find('/', 0); 5838bf80f4bSopenharmony_ci BASE_NS::string_view step = path.substr(0, pos); 5848bf80f4bSopenharmony_ci node = interface_pointer_cast<SCENE_NS::INode>(container->FindByName(step)); 5858bf80f4bSopenharmony_ci if (node) { 5868bf80f4bSopenharmony_ci if (pos == BASE_NS::string_view::npos) { 5878bf80f4bSopenharmony_ci return node; 5888bf80f4bSopenharmony_ci } 5898bf80f4bSopenharmony_ci path = path.substr(pos + 1); 5908bf80f4bSopenharmony_ci } 5918bf80f4bSopenharmony_ci } 5928bf80f4bSopenharmony_ci } 5938bf80f4bSopenharmony_ci return {}; 5948bf80f4bSopenharmony_ci} 5958bf80f4bSopenharmony_cinapi_value NodeImpl::GetNodeByPath(NapiApi::FunctionContext<BASE_NS::string>& ctx) 5968bf80f4bSopenharmony_ci{ 5978bf80f4bSopenharmony_ci BASE_NS::string path = ctx.Arg<0>(); 5988bf80f4bSopenharmony_ci auto meta = GetThisNativeObject(ctx); 5998bf80f4bSopenharmony_ci if (!meta) { 6008bf80f4bSopenharmony_ci return ctx.GetNull(); 6018bf80f4bSopenharmony_ci } 6028bf80f4bSopenharmony_ci 6038bf80f4bSopenharmony_ci META_NS::IObject::Ptr child; 6048bf80f4bSopenharmony_ci if (auto node = interface_pointer_cast<SCENE_NS::INode>(meta)) { 6058bf80f4bSopenharmony_ci ExecSyncTask([node, &child, path]() { 6068bf80f4bSopenharmony_ci // make sure the child objects exist 6078bf80f4bSopenharmony_ci child = interface_pointer_cast<META_NS::IObject>(recurse_children(node, path)); 6088bf80f4bSopenharmony_ci return META_NS::IAny::Ptr {}; 6098bf80f4bSopenharmony_ci }); 6108bf80f4bSopenharmony_ci } 6118bf80f4bSopenharmony_ci 6128bf80f4bSopenharmony_ci if (!child) { 6138bf80f4bSopenharmony_ci // no such child. 6148bf80f4bSopenharmony_ci return ctx.GetNull(); 6158bf80f4bSopenharmony_ci } 6168bf80f4bSopenharmony_ci 6178bf80f4bSopenharmony_ci if (auto cached = FetchJsObj(child)) { 6188bf80f4bSopenharmony_ci // always return the same js object. 6198bf80f4bSopenharmony_ci return cached; 6208bf80f4bSopenharmony_ci } 6218bf80f4bSopenharmony_ci 6228bf80f4bSopenharmony_ci if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) { 6238bf80f4bSopenharmony_ci CORE_LOG_F("INVALID SCENE!"); 6248bf80f4bSopenharmony_ci } 6258bf80f4bSopenharmony_ci 6268bf80f4bSopenharmony_ci // create new js object for the native node. 6278bf80f4bSopenharmony_ci NapiApi::Object argJS(ctx); 6288bf80f4bSopenharmony_ci napi_value args[] = { scene_.GetValue(), argJS }; 6298bf80f4bSopenharmony_ci 6308bf80f4bSopenharmony_ci return CreateFromNativeInstance(ctx, child, false /*these are owned by the scene*/, BASE_NS::countof(args), args); 6318bf80f4bSopenharmony_ci} 632