• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "GeometryJS.h"
16 
17 #include <meta/api/make_callback.h>
18 #include <meta/interface/intf_task_queue.h>
19 #include <meta/interface/intf_task_queue_registry.h>
20 #include <scene/ext/intf_internal_scene.h>
21 #include <scene/interface/intf_camera.h>
22 #include <scene/interface/intf_mesh.h>
23 #include <scene/interface/intf_mesh_resource.h>
24 #include <scene/interface/intf_scene.h>
25 
26 #include "MeshResourceJS.h"
27 #include "SceneJS.h"
28 #include "geometry_definition/GeometryDefinition.h"
29 
GetInstanceImpl(uint32_t id)30 void* GeometryJS::GetInstanceImpl(uint32_t id)
31 {
32     if (id == GeometryJS::ID) {
33         return this;
34     }
35     return NodeImpl::GetInstanceImpl(id);
36 }
DisposeNative(void * scn)37 void GeometryJS::DisposeNative(void* scn)
38 {
39     if (disposed_) {
40         return;
41     }
42     LOG_V("GeometryJS::DisposeNative");
43     disposed_ = true;
44 
45     SceneJS* sceneJS = static_cast<SceneJS*>(scn);
46     if (sceneJS) {
47         sceneJS->ReleaseDispose(reinterpret_cast<uintptr_t>(&scene_));
48     }
49 
50     if (auto node = interface_pointer_cast<SCENE_NS::INode>(GetNativeObject())) {
51         if (!IsAttached()) {
52             if (auto access = interface_pointer_cast<SCENE_NS::IMeshAccess>(node)) {
53                 access->SetMesh(nullptr).Wait();
54             }
55             if (auto scene = node->GetScene()) {
56                 scene->RemoveNode(BASE_NS::move(node)).Wait();
57             }
58         }
59         // reset the native object refs
60         SetNativeObject(nullptr, false);
61         SetNativeObject(nullptr, true);
62     }
63     scene_.Reset();
64 }
Init(napi_env env,napi_value exports)65 void GeometryJS::Init(napi_env env, napi_value exports)
66 {
67     BASE_NS::vector<napi_property_descriptor> node_props;
68     NodeImpl::GetPropertyDescs(node_props);
69 
70     using namespace NapiApi;
71     node_props.push_back(GetProperty<Object, GeometryJS, &GeometryJS::GetMesh>("mesh"));
72 
73     napi_value func;
74     auto status = napi_define_class(env, "Geometry", NAPI_AUTO_LENGTH, BaseObject::ctor<GeometryJS>(), nullptr,
75         node_props.size(), node_props.data(), &func);
76 
77     NapiApi::MyInstanceState* mis;
78     GetInstanceData(env, (void**)&mis);
79     mis->StoreCtor("Geometry", func);
80 }
81 
GeometryJS(napi_env e,napi_callback_info i)82 GeometryJS::GeometryJS(napi_env e, napi_callback_info i) : BaseObject<GeometryJS>(e, i), NodeImpl(NodeImpl::GEOMETRY)
83 {
84     LOG_V("GeometryJS ++ ");
85 
86     // Resolve overload with 2 or 3 given args.
87     if (auto ctx = NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> { e, i }) {
88         Construct(e, ctx.This(), ctx.Arg<0>(), ctx.Arg<1>());
89     } else if (auto ctx = NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object, NapiApi::Object> { e, i }) {
90         // Manual creation with an extra arg.
91         if (Construct(e, ctx.This(), ctx.Arg<0>(), ctx.Arg<1>()) == ConstructionState::LACKS_NATIVE) {
92             CreateNativeObject(e, ctx.This(), ctx.Arg<1>(), ctx.Arg<2>()); // 2: index
93         }
94     } else {
95         LOG_E("Bad args given for GeometryJS constructor");
96         return;
97     }
98 }
~GeometryJS()99 GeometryJS::~GeometryJS()
100 {
101     LOG_V("GeometryJS -- ");
102 }
103 
Finalize(napi_env env)104 void GeometryJS::Finalize(napi_env env)
105 {
106     DisposeNative(GetJsWrapper<SceneJS>(scene_.GetObject()));
107     BaseObject::Finalize(env);
108 }
Construct(napi_env env,NapiApi::Object meJs,NapiApi::Object scene,NapiApi::Object sceneNodeParameters)109 GeometryJS::ConstructionState GeometryJS::Construct(
110     napi_env env, NapiApi::Object meJs, NapiApi::Object scene, NapiApi::Object sceneNodeParameters)
111 {
112     if (!GetNativeMeta<SCENE_NS::IScene>(scene)) {
113         LOG_F("Invalid scene for GeometryJS!");
114         return ConstructionState::FAILED;
115     }
116     scene_ = NapiApi::WeakRef { env, scene.ToNapiValue() };
117 
118     // Add the dispose hook to scene so that the Geometry node is disposed when scene is disposed.
119     if (auto sceneJS = GetJsWrapper<SceneJS>(scene)) {
120         sceneJS->DisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
121     }
122 
123     if (const auto name = sceneNodeParameters.Get<BASE_NS::string>("name"); name.IsValid()) {
124         meJs.Set("name", name);
125     }
126 
127     auto nativeObject = GetNativeObjectParam<META_NS::IObject>(sceneNodeParameters);
128     if (nativeObject) {
129         StoreJsObj(nativeObject, meJs);
130         return ConstructionState::FINISHED;
131     }
132     return ConstructionState::LACKS_NATIVE;
133 }
134 
CreateNativeObject(napi_env env,NapiApi::Object meJs,NapiApi::Object sceneNodeParameters,NapiApi::Object meshResourceParam)135 void GeometryJS::CreateNativeObject(
136     napi_env env, NapiApi::Object meJs, NapiApi::Object sceneNodeParameters, NapiApi::Object meshResourceParam)
137 {
138     auto name = BASE_NS::string {};
139     auto path = BASE_NS::string {};
140     if (auto param = sceneNodeParameters.Get("name")) {
141         name = NapiApi::Value<BASE_NS::string>(env, param).valueOrDefault("");
142     }
143     if (auto param = sceneNodeParameters.Get("path")) {
144         path = NapiApi::Value<BASE_NS::string>(env, param).valueOrDefault("");
145     }
146 
147     auto nodePath = BASE_NS::string {};
148     if (!path.empty()) {
149         nodePath = path;
150     } else if (!name.empty()) {
151         // Use the name as path. Create the node directly under root.
152         nodePath = name;
153     }
154 
155     auto scene = GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject());
156     // Node creation can fail e.g. due to a bad path. Then we're going to have a null Geometry object.
157     auto meshNode = scene->CreateNode(nodePath, SCENE_NS::ClassId::MeshNode).GetResult();
158     if (auto access = interface_pointer_cast<SCENE_NS::IMeshAccess>(meshNode)) {
159         const auto resource = static_cast<MeshResourceJS*>(meshResourceParam.Native<TrueRootObject>());
160         const auto mesh = resource->CreateMesh();
161         access->SetMesh(mesh).GetResult();
162     }
163     // Always set regardless of success.
164     SetNativeObject(interface_pointer_cast<META_NS::IObject>(meshNode), false);
165     StoreJsObj(GetNativeObject(), meJs);
166 }
GetMesh(NapiApi::FunctionContext<> & ctx)167 napi_value GeometryJS::GetMesh(NapiApi::FunctionContext<>& ctx)
168 {
169     if (!validateSceneRef()) {
170         return ctx.GetUndefined();
171     }
172 
173     META_NS::IObject::Ptr mesh = GetNativeObject();
174     if (!interface_cast<SCENE_NS::IMesh>(mesh)) {
175         mesh = nullptr;
176     }
177 
178     if (!mesh) {
179         // no mesh.
180         return ctx.GetNull();
181     }
182 
183     if (auto cached = FetchJsObj(mesh, "_JSWMesh")) {
184         // always return the same js object.
185         return cached.ToNapiValue();
186     }
187     // create new js object for the native node.
188     NapiApi::Env env(ctx.Env());
189     NapiApi::Object argJS(env);
190     napi_value args[] = { scene_.GetValue(), argJS.ToNapiValue() };
191 
192     MakeNativeObjectParam(env, mesh, BASE_NS::countof(args), args);
193 
194     auto nodeJS = CreateJsObj(env, "Mesh", mesh, false, BASE_NS::countof(args), args);
195     if (!nodeJS) {
196         LOG_E("Could not create JSObject for Class %s", "Mesh");
197         return {};
198     }
199     return StoreJsObj(mesh, nodeJS, "_JSWMesh").ToNapiValue();
200 }