• 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 
16 #include "SceneJS.h"
17 #include "LightJS.h"
18 #include "MaterialJS.h"
19 static constexpr BASE_NS::Uid IO_QUEUE { "be88e9a0-9cd8-45ab-be48-937953dc258f" };
20 #include <meta/api/make_callback.h>
21 #include <meta/interface/intf_task_queue.h>
22 #include <meta/interface/intf_task_queue_registry.h>
23 #include <meta/interface/property/property_events.h>
24 #include <scene_plugin/api/camera.h> //for the classid...
25 #include <scene_plugin/api/environment_uid.h>
26 #include <scene_plugin/api/material_uid.h>
27 #include <scene_plugin/api/render_configuration_uid.h>
28 #include <scene_plugin/api/scene_uid.h>
29 #include <scene_plugin/interface/intf_ecs_scene.h>
30 #include <scene_plugin/interface/intf_material.h>
31 #include <scene_plugin/interface/intf_render_configuration.h>
32 #include <scene_plugin/interface/intf_scene.h>
33 
34 #include <core/image/intf_image_loader_manager.h>
35 #include <core/intf_engine.h>
36 #include <render/device/intf_gpu_resource_manager.h>
37 #include <render/intf_render_context.h>
38 
39 #ifdef __SCENE_ADAPTER__
40 #include "3d_widget_adapter_log.h"
41 #include "scene_adapter/scene_adapter.h"
42 #endif
43 
44 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
45 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
46 
47 static META_NS::ITaskQueue::Ptr releaseThread;
48 static constexpr BASE_NS::Uid JS_RELEASE_THREAD { "3784fa96-b25b-4e9c-bbf1-e897d36f73af" };
49 
Init(napi_env env,napi_value exports)50 void SceneJS::Init(napi_env env, napi_value exports)
51 {
52     using namespace NapiApi;
53     // clang-format off
54     auto loadFun = [](napi_env e,napi_callback_info cb) -> napi_value
55         {
56             FunctionContext<> fc(e,cb);
57             return SceneJS::Load(fc);
58         };
59 
60     napi_property_descriptor props[] = {
61         // static methods
62         napi_property_descriptor{ "load", nullptr, loadFun, nullptr, nullptr, nullptr, (napi_property_attributes)(napi_static|napi_default_method)},
63         // properties
64         GetSetProperty<NapiApi::Object, SceneJS, &SceneJS::GetEnvironment, &SceneJS::SetEnvironment>("environment"),
65         GetProperty<NapiApi::Array,SceneJS, &SceneJS::GetAnimations>("animations"),
66         // animations
67         GetProperty<BASE_NS::string, SceneJS, &SceneJS::GetRoot>("root"),
68         // scene methods
69         Method<NapiApi::FunctionContext<BASE_NS::string>, SceneJS, &SceneJS::GetNode>("getNodeByPath"),
70         Method<NapiApi::FunctionContext<>, SceneJS, &SceneJS::GetResourceFactory>("getResourceFactory"),
71         Method<NapiApi::FunctionContext<>, SceneJS, &SceneJS::Dispose>("destroy"),
72         Method<NapiApi::FunctionContext<>, SceneJS, &SceneJS::RenderFrame>("renderFrame"),
73 
74         // SceneResourceFactory methods
75         Method<NapiApi::FunctionContext<NapiApi::Object>, SceneJS, &SceneJS::CreateCamera>("createCamera"),
76         Method<NapiApi::FunctionContext<NapiApi::Object,uint32_t>, SceneJS, &SceneJS::CreateLight>("createLight"),
77         Method<NapiApi::FunctionContext<NapiApi::Object>, SceneJS, &SceneJS::CreateNode>("createNode"),
78         Method<NapiApi::FunctionContext<NapiApi::Object,uint32_t>, SceneJS, &SceneJS::CreateMaterial>("createMaterial"),
79         Method<NapiApi::FunctionContext<NapiApi::Object>, SceneJS, &SceneJS::CreateShader>("createShader"),
80         Method<NapiApi::FunctionContext<NapiApi::Object>, SceneJS, &SceneJS::CreateImage>("createImage"),
81         Method<NapiApi::FunctionContext<NapiApi::Object>, SceneJS, &SceneJS::CreateEnvironment>("createEnvironment")
82     };
83     // clang-format on
84 
85     napi_value func;
86     auto status = napi_define_class(env, "Scene", NAPI_AUTO_LENGTH, BaseObject::ctor<SceneJS>(), nullptr,
87         sizeof(props) / sizeof(props[0]), props, &func);
88 
89     napi_set_named_property(env, exports, "Scene", func);
90 
91     NapiApi::MyInstanceState* mis;
92     GetInstanceData(env, (void**)&mis);
93     mis->StoreCtor("Scene", func);
94 }
95 class AsyncStateBase {
96 public:
~AsyncStateBase()97     virtual ~AsyncStateBase()
98     {
99         // assert that the promise has been fulfilled.
100         CORE_ASSERT(deferred == nullptr);
101         // assert that the threadsafe func has been released.
102         CORE_ASSERT(termfun == nullptr);
103     }
104 
105     // inherit from this
106     napi_deferred deferred { nullptr };
107     napi_threadsafe_function termfun { nullptr };
108     napi_value result { nullptr };
109     virtual bool finally(napi_env env) = 0;
110     template<typename A>
Flip(A & a)111     A Flip(A& a)
112     {
113         A tmp = a;
114         a = nullptr;
115         return tmp;
116     }
CallIt()117     void CallIt()
118     {
119         // should be called from engine thread only.
120         // use an extra task in engine to trigger this
121         // to woraround an issue wherer CallIt is called IN an eventhandler.
122         // as there seems to be cases where (uncommon, have no repro. but has happend)
123         // napi_release_function waits for threadsafe function completion
124         // and the "js function" is waiting for the enghen thread (which is blocked releasing the function)
125         if (auto tf = Flip(termfun)) {
126             META_NS::GetTaskQueueRegistry()
127                 .GetTaskQueue(JS_RELEASE_THREAD)
128                 ->AddTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(BASE_NS::move([tf]() {
129                     napi_call_threadsafe_function(tf, nullptr, napi_threadsafe_function_call_mode::napi_tsfn_blocking);
130                     napi_release_threadsafe_function(tf, napi_threadsafe_function_release_mode::napi_tsfn_release);
131                     return false;
132                 })));
133         }
134     }
135     // callable from js thread
Fail(napi_env env)136     void Fail(napi_env env)
137     {
138         napi_status status;
139         if (auto df = Flip(deferred)) {
140             status = napi_reject_deferred(env, df, result);
141         }
142         if (auto tf = Flip(termfun)) {
143             // if called from java thread. then release it here...
144             napi_release_threadsafe_function(tf, napi_threadsafe_function_release_mode::napi_tsfn_release);
145         }
146     }
Success(napi_env env)147     void Success(napi_env env)
148     {
149         napi_status status;
150         // return success
151         if (auto df = Flip(deferred)) {
152             status = napi_resolve_deferred(env, df, result);
153         }
154         if (auto tf = Flip(termfun)) {
155             // if called from java thread. then release it here...
156             napi_release_threadsafe_function(tf, napi_threadsafe_function_release_mode::napi_tsfn_release);
157         }
158     }
159 };
MakePromise(napi_env env,AsyncStateBase * data)160 napi_value MakePromise(napi_env env, AsyncStateBase* data)
161 {
162     napi_value promise;
163     napi_status status = napi_create_promise(env, &data->deferred, &promise);
164     napi_value name;
165     napi_create_string_latin1(env, "a", 1, &name);
166     status = napi_create_threadsafe_function(
167         env, nullptr, nullptr, name, 1, 1, data /*finalize_data*/,
168         [](napi_env env, void* finalize_data, void* finalize_hint) {
169             AsyncStateBase* data = (AsyncStateBase*)finalize_data;
170             delete data;
171         },
172         data /*context*/,
173         [](napi_env env, napi_value js_callback, void* context, void* inData) {
174             // IN JS THREAD. (so careful with the calls to engine)
175             napi_status status;
176             AsyncStateBase* data = (AsyncStateBase*)context;
177             status = napi_get_undefined(env, &data->result);
178             if (data->finally(env)) {
179                 data->Success(env);
180             } else {
181                 data->Fail(env);
182             }
183         },
184         &data->termfun);
185     return promise;
186 }
FetchResourceOrUri(napi_env e,napi_value arg)187 BASE_NS::string FetchResourceOrUri(napi_env e, napi_value arg)
188 {
189     napi_valuetype type;
190     napi_typeof(e, arg, &type);
191     if (type == napi_string) {
192         BASE_NS::string uri = NapiApi::Value<BASE_NS::string>(e, arg);
193         // set default format as system resource
194         uri.insert(0, "file://");
195         return uri;
196     }
197     if (type == napi_object) {
198         NapiApi::Object resource(e, arg);
199         uint32_t id = resource.Get<uint32_t>("id");
200         uint32_t type = resource.Get<uint32_t>("type");
201         NapiApi::Array parms = resource.Get<NapiApi::Array>("params");
202         BASE_NS::string uri;
203         if ((id == 0) && (type == 30000)) {
204             // seems like a correct rawfile.
205             uri = parms.Get<BASE_NS::string>(0);
206         }
207         if (!uri.empty()) {
208             // add the schema then
209             uri.insert(0, "OhosRawFile://");
210         }
211         return uri;
212     }
213     return "";
214 }
215 
FetchResourceOrUri(NapiApi::FunctionContext<> & ctx)216 BASE_NS::string FetchResourceOrUri(NapiApi::FunctionContext<>& ctx)
217 {
218     BASE_NS::string uri;
219     NapiApi::FunctionContext<NapiApi::Object> resourceContext(ctx);
220     NapiApi::FunctionContext<BASE_NS::string> uriContext(ctx);
221 
222     if (uriContext) {
223         // actually not supported anymore.
224         uri = uriContext.Arg<0>();
225         // check if there is a protocol
226         auto t = uri.find("://");
227         if (t == BASE_NS::string::npos) {
228             // no proto . so use default
229             // set default format as system resource
230             uri.insert(0, "file://");
231         }
232     } else if (resourceContext) {
233         // get it from resource then
234         NapiApi::Object resource = resourceContext.Arg<0>();
235         uint32_t id = resource.Get<uint32_t>("id");
236         uint32_t type = resource.Get<uint32_t>("type");
237         NapiApi::Array parms = resource.Get<NapiApi::Array>("params");
238         if ((id == 0) && (type == 30000)) { // 30000 : type
239             // seems like a correct rawfile.
240             uri = parms.Get<BASE_NS::string>(0);
241         }
242         if (!uri.empty()) {
243             // add the schema then
244             uri.insert(0, "OhosRawFile://");
245         }
246     }
247     return uri;
248 }
249 
Load(NapiApi::FunctionContext<> & ctx)250 napi_value SceneJS::Load(NapiApi::FunctionContext<>& ctx)
251 {
252     BASE_NS::string uri = FetchResourceOrUri(ctx);
253 
254     if (uri.empty()) {
255         // unsupported input..
256         return {};
257     }
258     // make sure slashes are correct.. *eh*
259     for (;;) {
260         auto t = uri.find_first_of('\\');
261         if (t == BASE_NS::string::npos) {
262             break;
263         }
264         uri[t] = '/';
265     }
266 
267     auto &tr = META_NS::GetTaskQueueRegistry();
268     releaseThread = META_NS::GetTaskQueueRegistry().GetTaskQueue(JS_RELEASE_THREAD);
269     if (!releaseThread) {
270         auto &obr = META_NS::GetObjectRegistry();
271         releaseThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
272         tr.RegisterTaskQueue(releaseThread, JS_RELEASE_THREAD);
273     }
274 
275     struct AsyncState : public AsyncStateBase {
276         BASE_NS::string uri;
277         SCENE_NS::IScene::Ptr scene;
278         META_NS::IEvent::Token onLoadedToken { 0 };
279         bool finally(napi_env env) override
280         {
281             if (scene) {
282                 auto obj = interface_pointer_cast<META_NS::IObject>(scene);
283                 result = CreateJsObj(env, "Scene", obj, true, 0, nullptr);
284                 // link the native object to js object.
285                 StoreJsObj(obj, { env, result });
286 
287                 NapiApi::Object me(env, result);
288                 auto curenv = me.Get<NapiApi::Object>("environment");
289                 if (!curenv) {
290                     // setup default env
291                     NapiApi::Object argsIn(env);
292                     argsIn.Set("name", "DefaultEnv");
293 
294                     auto* tro = (SceneJS*)(me.Native<TrueRootObject>());
295                     auto res = tro->CreateEnvironment(me, argsIn);
296                     res.Set("backgroundType", NapiApi::Value<uint32_t>(env, 1)); // image.. but with null.
297                     me.Set("environment", res);
298                 }
299 
300 #ifdef __SCENE_ADAPTER__
301                 // set SceneAdapter
302                 auto oo = GetRootObject(env, result);
303 
304                 auto sceneAdapter = std::make_shared<OHOS::Render3D::SceneAdapter>();
305                 sceneAdapter->SetSceneObj(oo->GetNativeObject());
306                 auto sceneJs = static_cast<SceneJS*>(oo);
307                 sceneJs->scene_ = sceneAdapter;
308 #endif
309                 return true;
310             }
311             scene.reset();
312             return false;
313         };
314     };
315     AsyncState* data = new AsyncState();
316     data->uri = uri;
317 
318     auto fun = [data]() {
319         // IN ENGINE THREAD! (so no js calls)
320         using namespace SCENE_NS;
321         auto& obr = META_NS::GetObjectRegistry();
322         auto params = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
323         auto scene = interface_pointer_cast<SCENE_NS::IScene>(obr.Create(SCENE_NS::ClassId::Scene, params));
324         if (!scene) {
325             // insta fail
326             data->CallIt();
327             return false;
328         }
329         data->scene = scene;
330 
331         auto onLoaded = META_NS::MakeCallback<META_NS::IOnChanged>([data]() {
332             bool complete = false;
333             auto scene = data->scene;
334             auto status = scene->Status()->GetValue();
335             if (status == SCENE_NS::IScene::SCENE_STATUS_READY) {
336                 // still in engine thread..
337                 complete = true;
338             } else if (status == SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED) {
339                 data->scene.reset(); // make sure we don't have anything in result if error.
340                 complete = true;
341             }
342 
343             if (complete) {
344                 scene->Status()->OnChanged()->RemoveHandler(data->onLoadedToken);
345                 data->onLoadedToken = 0;
346                 if (scene) {
347                     auto& obr = META_NS::GetObjectRegistry();
348                     // make sure we have renderconfig
349                     auto rc = scene->RenderConfiguration()->GetValue();
350                     if (!rc) {
351                         // Create renderconfig
352                         rc = obr.Create<SCENE_NS::IRenderConfiguration>(SCENE_NS::ClassId::RenderConfiguration);
353                         scene->RenderConfiguration()->SetValue(rc);
354                     }
355                     /*if (auto env = rc->Environment()->GetValue(); !env) {
356                         // create default env then
357                         env = scene->CreateNode<SCENE_NS::IEnvironment>("default_env");
358                         env->Background()->SetValue(SCENE_NS::IEnvironment::CUBEMAP);
359                         rc->Environment()->SetValue(env);
360                     }*/
361 
362                     interface_cast<IEcsScene>(scene)->RenderMode()->SetValue(IEcsScene::RenderMode::RENDER_ALWAYS);
363                     auto params = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
364                     auto duh = params->GetArrayPropertyByName<IntfWeakPtr>("Scenes");
365                     duh->AddValue(interface_pointer_cast<CORE_NS::IInterface>(scene));
366                 }
367                 // call the threadsafe func here. (let the javascript know we are done)
368                 data->CallIt();
369             }
370         });
371         data->onLoadedToken = scene->Status()->OnChanged()->AddHandler(onLoaded);
372         scene->Asynchronous()->SetValue(false);
373         scene->Uri()->SetValue(data->uri);
374         return false;
375     };
376     // Should it be possible to cancel? (ie. do we need to store the token for something..)
377     META_NS::GetTaskQueueRegistry()
378         .GetTaskQueue(ENGINE_THREAD)
379         ->AddTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(BASE_NS::move(fun)));
380 
381     return MakePromise(ctx, data);
382 }
383 
RenderFrame(NapiApi::FunctionContext<> & ctx)384 napi_value SceneJS::RenderFrame(NapiApi::FunctionContext<>& ctx)
385 {
386     if (ctx.ArgCount() > 1) {
387         CORE_LOG_E("render frame %d", __LINE__);
388         return ctx.GetUndefined();
389     }
390     bool res = true;
391 #ifdef __SCENE_ADAPTER__
392     auto sceneAdapter = std::static_pointer_cast<OHOS::Render3D::SceneAdapter>(scene_);
393     if (sceneAdapter) {
394         sceneAdapter->SetNeedsRepaint(false);
395         sceneAdapter->RenderFrame(false);
396     }
397 #endif
398     return ctx.GetBoolean(res);
399 }
400 
Dispose(NapiApi::FunctionContext<> & ctx)401 napi_value SceneJS::Dispose(NapiApi::FunctionContext<>& ctx)
402 {
403     LOG_F("SCENE_JS::Dispose");
404     DisposeNative();
405     return {};
406 }
DisposeNative()407 void SceneJS::DisposeNative()
408 {
409     LOG_F("SCENE_JS::DisposeNative");
410     // dispose
411     while (!disposables_.empty()) {
412         auto env = disposables_.begin()->second.GetObject();
413         if (env) {
414             NapiApi::Function func = env.Get<NapiApi::Function>("destroy");
415             if (func) {
416                 func.Invoke(env);
417             }
418         }
419     }
420 
421     // dispose all cameras/env/etcs.
422     while (!strongDisposables_.empty()) {
423         auto it = strongDisposables_.begin();
424         auto token = it->first;
425         auto env = it->second.GetObject();
426         if (env) {
427             NapiApi::Function func = env.Get<NapiApi::Function>("destroy");
428             if (func) {
429                 func.Invoke(env);
430             }
431         }
432     }
433     if (auto env = environmentJS_.GetObject()) {
434         NapiApi::Function func = env.Get<NapiApi::Function>("destroy");
435         if (func) {
436             func.Invoke(env);
437         }
438     }
439     environmentJS_.Reset();
440     for (auto b : bitmaps_) {
441         b.second.reset();
442     }
443     if (auto scene = interface_pointer_cast<SCENE_NS::IScene>(GetNativeObject())) {
444         // reset the native object refs
445         SetNativeObject(nullptr, false);
446         SetNativeObject(nullptr, true);
447 
448         ExecSyncTask([scn = BASE_NS::move(scene)]() {
449             auto r = scn->RenderConfiguration()->GetValue();
450             auto e = r->Environment()->GetValue();
451             e.reset();
452             r.reset();
453             scn->RenderConfiguration()->SetValue(nullptr);
454             return META_NS::IAny::Ptr {};
455         });
456     }
457 }
GetInstanceImpl(uint32_t id)458 void* SceneJS::GetInstanceImpl(uint32_t id)
459 {
460     if (id == SceneJS::ID) {
461         return this;
462     }
463     return nullptr;
464 }
Finalize(napi_env env)465 void SceneJS::Finalize(napi_env env)
466 {
467     // hmm.. do i need to do something BEFORE the object gets deleted..
468     BaseObject<SceneJS>::Finalize(env);
469 }
470 
SceneJS(napi_env e,napi_callback_info i)471 SceneJS::SceneJS(napi_env e, napi_callback_info i) : BaseObject<SceneJS>(e, i)
472 {
473     LOG_F("SceneJS ++");
474     NapiApi::FunctionContext<NapiApi::Object> fromJs(e, i);
475 
476     if (!fromJs) {
477         // okay internal create. we will receive the object after.
478         return;
479     }
480 
481     // Construct native object
482     SCENE_NS::IScene::Ptr scene;
483     ExecSyncTask([&scene]() {
484         using namespace SCENE_NS;
485         auto& obr = META_NS::GetObjectRegistry();
486         auto params = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
487         scene = interface_pointer_cast<SCENE_NS::IScene>(obr.Create(SCENE_NS::ClassId::Scene, params));
488         if (scene) {
489             // only asynch false works.. (otherwise nodes are in random state when scene is ready.. )
490             scene->Asynchronous()->SetValue(false);
491             interface_cast<IEcsScene>(scene)->RenderMode()->SetValue(IEcsScene::RenderMode::RENDER_ALWAYS);
492             auto duh = params->GetArrayPropertyByName<IntfWeakPtr>("Scenes");
493             duh->AddValue(interface_pointer_cast<CORE_NS::IInterface>(scene));
494         }
495         return META_NS::IAny::Ptr {};
496     });
497 
498     // process constructor args..
499     NapiApi::Object meJs(e, fromJs.This());
500     SetNativeObject(interface_pointer_cast<META_NS::IObject>(scene), true /* KEEP STRONG REF */);
501     StoreJsObj(interface_pointer_cast<META_NS::IObject>(scene), meJs);
502 
503     NapiApi::Object args = fromJs.Arg<0>();
504     if (args) {
505         if (auto name = args.Get("name")) {
506             meJs.Set("name", name);
507         }
508         if (auto uri = args.Get("uri")) {
509             meJs.Set("uri", uri);
510         }
511     }
512 }
513 
~SceneJS()514 SceneJS::~SceneJS()
515 {
516     LOG_F("SceneJS --");
517     if (!GetNativeObject()) {
518         return;
519     }
520     ExecSyncTask([scene = GetNativeObject()]() {
521         auto& obr = META_NS::GetObjectRegistry();
522         auto params = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
523         auto duh = params->GetArrayPropertyByName<IntfWeakPtr>("Scenes");
524         if (duh) {
525             for (auto i = 0; i < duh->GetSize();) {
526                 auto w = duh->GetValueAt(i);
527                 if (w.lock() == nullptr) {
528                     duh->RemoveAt(i);
529                 } else {
530                     i++;
531                 }
532             }
533         }
534         return META_NS::IAny::Ptr {};
535     });
536 }
537 
GetNode(NapiApi::FunctionContext<BASE_NS::string> & ctx)538 napi_value SceneJS::GetNode(NapiApi::FunctionContext<BASE_NS::string>& ctx)
539 {
540     // verify that path starts from "correct root" and then let the root node handle the rest.
541     NapiApi::Object meJs(ctx, ctx.This());
542     NapiApi::Object root = meJs.Get<NapiApi::Object>("root");
543     BASE_NS::string rootName = root.Get<BASE_NS::string>("name");
544     NapiApi::Function func = root.Get<NapiApi::Function>("getNodeByPath");
545     BASE_NS::string path = ctx.Arg<0>();
546 
547     // remove the "root nodes name" (make sure it also matches though..)
548     auto pos = path.find('/', 0);
549     BASE_NS::string_view step = path.substr(0, pos);
550     if (step != rootName) {
551         // root not matching
552         return ctx.GetNull();
553     }
554 
555     if (pos != BASE_NS::string_view::npos) {
556         BASE_NS::string rest(path.substr(pos + 1));
557         napi_value newpath = nullptr;
558         napi_status status = napi_create_string_utf8(ctx, rest.c_str(), rest.length(), &newpath);
559         if (newpath) {
560             return func.Invoke(root, 1, &newpath);
561         }
562         return ctx.GetNull();
563     }
564     return root;
565 }
GetRoot(NapiApi::FunctionContext<> & ctx)566 napi_value SceneJS::GetRoot(NapiApi::FunctionContext<>& ctx)
567 {
568     if (auto scene = interface_cast<SCENE_NS::IScene>(GetNativeObject())) {
569         SCENE_NS::INode::Ptr root;
570         auto cb = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([scene, &root]() {
571             root = scene->RootNode()->GetValue();
572             if (root) {
573                 // make sure our direct descendants exist.
574                 root->BuildChildren(SCENE_NS::INode::BuildBehavior::NODE_BUILD_ONLY_DIRECT_CHILDREN);
575             }
576             return META_NS::IAny::Ptr {};
577         });
578         META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD)->AddWaitableTask(cb)->Wait();
579         auto obj = interface_pointer_cast<META_NS::IObject>(root);
580 
581         if (auto cached = FetchJsObj(obj)) {
582             // always return the same js object.
583             return cached;
584         }
585 
586         NapiApi::StrongRef sceneRef { ctx, ctx.This() };
587         if (!GetNativeMeta<SCENE_NS::IScene>(sceneRef.GetObject())) {
588             CORE_LOG_F("INVALID SCENE!");
589         }
590 
591         NapiApi::Object argJS(ctx);
592         napi_value args[] = { sceneRef.GetObject(), argJS };
593 
594         return CreateFromNativeInstance(ctx, obj, false /*these are owned by the scene*/, BASE_NS::countof(args), args);
595     }
596     return ctx.GetUndefined();
597 }
598 
GetEnvironment(NapiApi::FunctionContext<> & ctx)599 napi_value SceneJS::GetEnvironment(NapiApi::FunctionContext<>& ctx)
600 {
601     if (auto scene = interface_cast<SCENE_NS::IScene>(GetNativeObject())) {
602         SCENE_NS::IEnvironment::Ptr environment;
603         ExecSyncTask([scene, &environment]() {
604             auto rc = scene->RenderConfiguration()->GetValue();
605             if (rc) {
606                 environment = rc->Environment()->GetValue();
607             }
608             return META_NS::IAny::Ptr {};
609         });
610         if (environment) {
611             auto obj = interface_pointer_cast<META_NS::IObject>(environment);
612             if (auto cached = FetchJsObj(obj)) {
613                 // always return the same js object.
614                 return cached;
615             }
616 
617             NapiApi::StrongRef sceneRef { ctx, ctx.This() };
618             if (!GetNativeMeta<SCENE_NS::IScene>(sceneRef.GetObject())) {
619                 CORE_LOG_F("INVALID SCENE!");
620             }
621 
622             NapiApi::Object argJS(ctx);
623             napi_value args[] = { sceneRef.GetObject(), argJS };
624 
625             environmentJS_ = { ctx, CreateFromNativeInstance(ctx, obj, false, BASE_NS::countof(args), args) };
626             return environmentJS_.GetValue();
627         }
628     }
629     return ctx.GetNull();
630 }
631 
SetEnvironment(NapiApi::FunctionContext<NapiApi::Object> & ctx)632 void SceneJS::SetEnvironment(NapiApi::FunctionContext<NapiApi::Object>& ctx)
633 {
634     NapiApi::Object env = ctx.Arg<0>();
635 
636     if (auto currentlySet = environmentJS_.GetObject()) {
637         if ((napi_value)currentlySet == (napi_value)env) {
638             // setting the exactly the same environment. do nothing.
639             return;
640         }
641     }
642     environmentJS_.Reset();
643     if (env) {
644         environmentJS_ = { env };
645     }
646     SCENE_NS::IEnvironment::Ptr environment;
647     if (env) {
648         environment = GetNativeMeta<SCENE_NS::IEnvironment>(env);
649     }
650     if (auto scene = interface_cast<SCENE_NS::IScene>(GetNativeObject())) {
651         ExecSyncTask([scene, environment]() {
652             auto rc = scene->RenderConfiguration()->GetValue();
653             if (!rc) {
654                 // no render config, so create it.
655                 auto& obr = META_NS::GetObjectRegistry();
656                 rc = obr.Create<SCENE_NS::IRenderConfiguration>(SCENE_NS::ClassId::RenderConfiguration);
657                 scene->RenderConfiguration()->SetValue(rc);
658             }
659             if (rc) {
660                 rc->Environment()->SetValue(environment);
661             }
662             return META_NS::IAny::Ptr {};
663         });
664     }
665 }
666 
667 // resource factory
668 
GetResourceFactory(NapiApi::FunctionContext<> & ctx)669 napi_value SceneJS::GetResourceFactory(NapiApi::FunctionContext<>& ctx)
670 {
671     // just return this. as scene is the factory also.
672     return ctx.This();
673 }
CreateEnvironment(NapiApi::Object scene,NapiApi::Object argsIn)674 NapiApi::Object SceneJS::CreateEnvironment(NapiApi::Object scene, NapiApi::Object argsIn)
675 {
676     napi_env env = scene.GetEnv();
677     napi_value args[] = { scene, argsIn };
678     auto result = NapiApi::Object(GetJSConstructor(env, "Environment"), BASE_NS::countof(args), args);
679     auto ref = NapiApi::StrongRef { env, result };
680     return { env, ref.GetValue() };
681 }
CreateEnvironment(NapiApi::FunctionContext<NapiApi::Object> & ctx)682 napi_value SceneJS::CreateEnvironment(NapiApi::FunctionContext<NapiApi::Object>& ctx)
683 {
684     struct AsyncState : public AsyncStateBase {
685         NapiApi::StrongRef this_;
686         NapiApi::StrongRef args_;
687         bool finally(napi_env env) override
688         {
689             auto* tro = (SceneJS*)(this_.GetObject().Native<TrueRootObject>());
690             result = tro->CreateEnvironment(this_.GetObject(), args_.GetObject());
691             return true;
692         };
693     };
694     AsyncState* data = new AsyncState();
695     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
696     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
697     napi_value result = MakePromise(ctx, data);
698     // and just instantly complete it
699     data->finally(ctx);
700     data->Success(ctx);
701     return result;
702 }
703 
CreateCamera(NapiApi::FunctionContext<NapiApi::Object> & ctx)704 napi_value SceneJS::CreateCamera(NapiApi::FunctionContext<NapiApi::Object>& ctx)
705 {
706     struct AsyncState : public AsyncStateBase {
707         NapiApi::StrongRef this_;
708         NapiApi::StrongRef args_;
709         bool finally(napi_env env) override
710         {
711             napi_value args[] = {
712                 this_.GetValue(), // scene..
713                 args_.GetValue()  // params.
714             };
715             result = NapiApi::Object(GetJSConstructor(env, "Camera"), BASE_NS::countof(args), args);
716             return true;
717         };
718     };
719     AsyncState* data = new AsyncState();
720     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
721     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
722     napi_value result = MakePromise(ctx, data);
723     // and just instantly complete it
724     data->finally(ctx);
725     data->Success(ctx);
726     return result;
727 }
728 
CreateLight(NapiApi::FunctionContext<NapiApi::Object,uint32_t> & ctx)729 napi_value SceneJS::CreateLight(NapiApi::FunctionContext<NapiApi::Object, uint32_t>& ctx)
730 {
731     struct AsyncState : public AsyncStateBase {
732         NapiApi::StrongRef this_;
733         NapiApi::StrongRef args_;
734         uint32_t lightType_;
735         bool finally(napi_env env) override
736         {
737             napi_value args[] = {
738                 this_.GetValue(), // scene..
739                 args_.GetValue()  // params.
740             };
741             NapiApi::Function func;
742             switch (lightType_) {
743                 case BaseLight::DIRECTIONAL: {
744                     func = GetJSConstructor(env, "DirectionalLight");
745                     break;
746                 }
747                 case BaseLight::POINT: {
748                     func = GetJSConstructor(env, "PointLight");
749                     break;
750                 }
751                 case BaseLight::SPOT: {
752                     func = GetJSConstructor(env, "SpotLight");
753                     break;
754                 }
755                 default:
756                     break;
757             }
758             if (!func) {
759                 return false;
760             }
761             result = NapiApi::Object(func, BASE_NS::countof(args), args);
762             return true;
763         };
764     };
765     AsyncState* data = new AsyncState();
766     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
767     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
768     data->lightType_ = ctx.Arg<1>();
769     napi_value result = MakePromise(ctx, data);
770     // and just instantly complete it
771     data->finally(ctx);
772     data->Success(ctx);
773     return result;
774 }
775 
CreateNode(NapiApi::FunctionContext<NapiApi::Object> & ctx)776 napi_value SceneJS::CreateNode(NapiApi::FunctionContext<NapiApi::Object>& ctx)
777 {
778     struct AsyncState : public AsyncStateBase {
779         NapiApi::StrongRef this_;
780         NapiApi::StrongRef args_;
781         bool finally(napi_env env) override
782         {
783             napi_value args[] = {
784                 this_.GetValue(), // scene..
785                 args_.GetValue()  // params.
786             };
787             result = NapiApi::Object(GetJSConstructor(env, "Node"), BASE_NS::countof(args), args);
788             return true;
789         };
790     };
791     AsyncState* data = new AsyncState();
792     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
793     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
794 
795     napi_value ret = MakePromise(ctx, data);
796     // and just instantly complete it
797     data->finally(ctx);
798     data->Success(ctx);
799     return ret;
800 }
801 
CreateMaterial(NapiApi::FunctionContext<NapiApi::Object,uint32_t> & ctx)802 napi_value SceneJS::CreateMaterial(NapiApi::FunctionContext<NapiApi::Object, uint32_t>& ctx)
803 {
804     struct AsyncState : public AsyncStateBase {
805         NapiApi::StrongRef this_;
806         NapiApi::StrongRef args_;
807         uint32_t type_;
808         BASE_NS::string name_;
809         SCENE_NS::IMaterial::Ptr material_;
810         SCENE_NS::IScene::Ptr scene_;
811         bool finally(napi_env env) override
812         {
813             napi_value args[] = {
814                 this_.GetValue(), // scene..
815                 args_.GetValue()  // params.
816             };
817 
818             if (type_ == BaseMaterial::SHADER) {
819                 MakeNativeObjectParam(env, material_, BASE_NS::countof(args), args);
820                 NapiApi::Object materialJS(GetJSConstructor(env, "ShaderMaterial"), BASE_NS::countof(args), args);
821                 result = materialJS;
822             } else {
823                 // fail..
824                 material_.reset();
825             }
826             return true;
827         };
828     };
829     AsyncState* data = new AsyncState();
830     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
831     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
832     data->type_ = ctx.Arg<1>();
833     if (ctx.Arg<0>()) {
834         NapiApi::Object parms = ctx.Arg<0>();
835         data->name_ = parms.Get<BASE_NS::string>("name");
836     }
837 
838     napi_value result = MakePromise(ctx, data);
839     data->scene_ = interface_pointer_cast<SCENE_NS::IScene>(GetNativeObject());
840 
841     // create an engine task and complete it there..
842     auto fun = [data]() {
843         data->material_ = data->scene_->CreateMaterial(data->name_);
844         data->CallIt();
845         return false;
846     };
847 
848     META_NS::GetTaskQueueRegistry()
849         .GetTaskQueue(ENGINE_THREAD)
850         ->AddTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(BASE_NS::move(fun)));
851 
852     return result;
853 }
854 
CreateShader(NapiApi::FunctionContext<NapiApi::Object> & ctx)855 napi_value SceneJS::CreateShader(NapiApi::FunctionContext<NapiApi::Object>& ctx)
856 {
857     struct AsyncState : public AsyncStateBase {
858         NapiApi::StrongRef this_;
859         NapiApi::StrongRef args_;
860         BASE_NS::string uri_;
861         BASE_NS::string name_;
862         SCENE_NS::IShader::Ptr shader_;
863         bool finally(napi_env env) override
864         {
865             napi_value args[] = {
866                 this_.GetValue(), // scene..
867                 args_.GetValue()  // params.
868             };
869             NapiApi::Object parms(env, args[1]);
870 
871             napi_value null;
872             napi_get_null(env, &null);
873             parms.Set("Material", null); // not bound to anything...
874 
875             MakeNativeObjectParam(env, shader_, BASE_NS::countof(args), args);
876             NapiApi::Object shaderJS(GetJSConstructor(env, "Shader"), BASE_NS::countof(args), args);
877             result = shaderJS;
878 
879             return true;
880         };
881     };
882     AsyncState* data = new AsyncState();
883     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
884     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
885     if (ctx.Arg<0>()) {
886         NapiApi::Object parms = ctx.Arg<0>();
887         data->name_ = parms.Get<BASE_NS::string>("name");
888         data->uri_ = FetchResourceOrUri(ctx, parms.Get("uri"));
889     }
890 
891     napi_value result = MakePromise(ctx, data);
892 
893     auto fun = [data]() {
894         auto& obr = META_NS::GetObjectRegistry();
895         auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
896         auto renderContext = doc->GetPropertyByName<IntfPtr>("RenderContext")->GetValue();
897 
898         auto params =
899             interface_pointer_cast<META_NS::IMetadata>(META_NS::GetObjectRegistry().Create(META_NS::ClassId::Object));
900 
901         params->AddProperty(META_NS::ConstructProperty<IntfPtr>(
902             "RenderContext", renderContext, META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE));
903 
904         params->AddProperty(META_NS::ConstructProperty<BASE_NS::string>(
905             "uri", data->uri_, META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE));
906 
907         data->shader_ = META_NS::GetObjectRegistry().Create<SCENE_NS::IShader>(SCENE_NS::ClassId::Shader, params);
908         data->CallIt();
909         return false;
910     };
911 
912     META_NS::GetTaskQueueRegistry()
913         .GetTaskQueue(ENGINE_THREAD)
914         ->AddTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(BASE_NS::move(fun)));
915 
916     return result;
917 }
918 
StoreBitmap(BASE_NS::string_view uri,SCENE_NS::IBitmap::Ptr bitmap)919 void SceneJS::StoreBitmap(BASE_NS::string_view uri, SCENE_NS::IBitmap::Ptr bitmap)
920 {
921     CORE_NS::UniqueLock lock(mutex_);
922     if (bitmap) {
923         bitmaps_[uri] = bitmap;
924     } else {
925         // setting null. releases.
926         bitmaps_.erase(uri);
927     }
928 }
FetchBitmap(BASE_NS::string_view uri)929 SCENE_NS::IBitmap::Ptr SceneJS::FetchBitmap(BASE_NS::string_view uri)
930 {
931     CORE_NS::UniqueLock lock(mutex_);
932     auto it = bitmaps_.find(uri);
933     if (it != bitmaps_.end()) {
934         return it->second;
935     }
936     return {};
937 }
938 
CreateImage(NapiApi::FunctionContext<NapiApi::Object> & ctx)939 napi_value SceneJS::CreateImage(NapiApi::FunctionContext<NapiApi::Object>& ctx)
940 {
941     using namespace RENDER_NS;
942 
943     struct AsyncState : public AsyncStateBase {
944         NapiApi::StrongRef this_;
945         NapiApi::StrongRef args_;
946         BASE_NS::shared_ptr<IRenderContext> renderContext_;
947         BASE_NS::string name_;
948         BASE_NS::string uri_;
949         SCENE_NS::IBitmap::Ptr bitmap_;
950         RenderHandleReference imageHandle_;
951         SceneJS* owner_;
952         CORE_NS::IImageLoaderManager::LoadResult imageLoadResult_;
953         bool cached_ { false };
954         bool finally(napi_env env) override
955         {
956             if (!bitmap_) {
957                 // return the error string..
958                 napi_create_string_utf8(env, imageLoadResult_.error, NAPI_AUTO_LENGTH, &result);
959                 return false;
960             }
961             if (!cached_) {
962                 // create the jsobject if we don't have one.
963                 napi_value args[] = {
964                     this_.GetValue(), // scene..
965                     args_.GetValue()  // params.
966                 };
967                 MakeNativeObjectParam(env, bitmap_, BASE_NS::countof(args), args);
968                 owner_->StoreBitmap(uri_, BASE_NS::move(bitmap_));
969                 NapiApi::Object imageJS(GetJSConstructor(env, "Image"), BASE_NS::countof(args), args);
970                 result = imageJS;
971             }
972             return true;
973         };
974     };
975     AsyncState* data = new AsyncState();
976     data->owner_ = this;
977     data->this_ = NapiApi::StrongRef(ctx, ctx.This());
978     data->args_ = NapiApi::StrongRef(ctx, ctx.Arg<0>());
979 
980     NapiApi::Object args = ctx.Arg<0>();
981     if (args) {
982         if (auto n = args.Get<BASE_NS::string>("name")) {
983             data->name_ = n;
984         }
985         data->uri_ = FetchResourceOrUri(ctx, args.Get("uri"));
986     }
987 
988     napi_value result = MakePromise(ctx, data);
989     if (auto bitmap = FetchBitmap(data->uri_)) {
990         // no aliasing.. so the returned bitmaps name is.. the old one.
991         // *fix*
992         // oh we have it already, no need to do anything in engine side.
993         data->cached_ = true;
994         data->bitmap_ = bitmap;
995         auto obj = interface_pointer_cast<META_NS::IObject>(data->bitmap_);
996         data->result = FetchJsObj(obj);
997         data->Success(ctx);
998         return result;
999     }
1000 
1001     auto& obr = META_NS::GetObjectRegistry();
1002     auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
1003     data->renderContext_ =
1004         interface_pointer_cast<IRenderContext>(doc->GetPropertyByName<IntfPtr>("RenderContext")->GetValue());
1005 
1006     // create an IO task (to load the cpu data)
1007     auto fun = [data]() -> META_NS::IAny::Ptr {
1008         uint32_t imageLoaderFlags = CORE_NS::IImageLoaderManager::IMAGE_LOADER_GENERATE_MIPS;
1009         auto& imageLoaderMgr = data->renderContext_->GetEngine().GetImageLoaderManager();
1010         data->imageLoadResult_ = imageLoaderMgr.LoadImage(data->uri_, imageLoaderFlags);
1011         return {};
1012     };
1013 
1014     // create final engine task (to create gpu resource)
1015     auto fun2 = [data](const META_NS::IAny::Ptr&) -> META_NS::IAny::Ptr {
1016         if (!data->imageLoadResult_.success) {
1017             CORE_LOG_E("Could not load image asset: %s", data->imageLoadResult_.error);
1018             data->bitmap_ = nullptr;
1019         } else {
1020             auto& gpuResourceMgr = data->renderContext_->GetDevice().GetGpuResourceManager();
1021             RenderHandleReference imageHandle {};
1022             GpuImageDesc gpuDesc = gpuResourceMgr.CreateGpuImageDesc(data->imageLoadResult_.image->GetImageDesc());
1023             gpuDesc.usageFlags = CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_TRANSFER_DST_BIT;
1024             if (gpuDesc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS) {
1025                 gpuDesc.usageFlags |= CORE_IMAGE_USAGE_TRANSFER_SRC_BIT;
1026             }
1027             gpuDesc.memoryPropertyFlags = CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1028             data->imageHandle_ = gpuResourceMgr.Create(data->uri_, gpuDesc, std::move(data->imageLoadResult_.image));
1029             data->bitmap_ = META_NS::GetObjectRegistry().Create<SCENE_NS::IBitmap>(SCENE_NS::ClassId::Bitmap);
1030             data->bitmap_->Uri()->SetValue(data->uri_);
1031             data->bitmap_->SetRenderHandle(data->imageHandle_, { gpuDesc.width, gpuDesc.height });
1032         }
1033         data->CallIt();
1034         return {};
1035     };
1036 
1037     // execute first step in io thread..
1038     // second in engine thread.
1039     // and the final in js thread (with threadsafefunction)
1040     auto ioqueue = META_NS::GetTaskQueueRegistry().GetTaskQueue(IO_QUEUE);
1041     auto enginequeue = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
1042     ioqueue->AddWaitableTask(META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>(BASE_NS::move(fun)))
1043         ->Then(META_NS::MakeCallback<META_NS::IFutureContinuation>(BASE_NS::move(fun2)), enginequeue);
1044 
1045     return result;
1046 }
GetAnimations(NapiApi::FunctionContext<> & ctx)1047 napi_value SceneJS::GetAnimations(NapiApi::FunctionContext<>& ctx)
1048 {
1049     auto scene = interface_pointer_cast<SCENE_NS::IScene>(GetThisNativeObject(ctx));
1050     if (!scene) {
1051         return ctx.GetUndefined();
1052     }
1053 
1054     BASE_NS::vector<META_NS::IAnimation::Ptr> animRes;
1055     ExecSyncTask([scene, &animRes]() {
1056         animRes = scene->GetAnimations();
1057         return META_NS::IAny::Ptr {};
1058     });
1059 
1060     napi_value tmp;
1061     auto status = napi_create_array_with_length(ctx, animRes.size(), &tmp);
1062     size_t i = 0;
1063     napi_value args[] = { ctx.This() };
1064     for (const auto& node : animRes) {
1065         napi_value val;
1066         val = CreateFromNativeInstance(
1067             ctx, interface_pointer_cast<META_NS::IObject>(node), false, BASE_NS::countof(args), args);
1068         status = napi_set_element(ctx, tmp, i++, val);
1069 
1070         // disposables_[
1071     }
1072 
1073     return tmp;
1074 }
1075 
DisposeHook(uintptr_t token,NapiApi::Object obj)1076 void SceneJS::DisposeHook(uintptr_t token, NapiApi::Object obj)
1077 {
1078     disposables_[token] = { obj };
1079 }
ReleaseDispose(uintptr_t token)1080 void SceneJS::ReleaseDispose(uintptr_t token)
1081 {
1082     auto it = disposables_.find(token);
1083     if (it != disposables_.end()) {
1084         it->second.Reset();
1085         disposables_.erase(it->first);
1086     }
1087 }
1088 
StrongDisposeHook(uintptr_t token,NapiApi::Object obj)1089 void SceneJS::StrongDisposeHook(uintptr_t token, NapiApi::Object obj)
1090 {
1091     strongDisposables_[token] = { obj };
1092 }
ReleaseStrongDispose(uintptr_t token)1093 void SceneJS::ReleaseStrongDispose(uintptr_t token)
1094 {
1095     auto it = strongDisposables_.find(token);
1096     if (it != strongDisposables_.end()) {
1097         it->second.Reset();
1098         strongDisposables_.erase(it->first);
1099     }
1100 }
1101 
1102 #ifdef __OHOS_PLATFORM__
1103 // This will circumvent the broken napi_set_instance_data and napi_get_instance_data implementations
1104 // on ohos platform
1105 static void* g_instanceData = nullptr;
1106 
SetInstanceData(napi_env env,void * data,napi_finalize finalizeCb,void * finalizeHint)1107 napi_status SetInstanceData(napi_env env, void* data, napi_finalize finalizeCb, void* finalizeHint)
1108 {
1109     g_instanceData = data;
1110     return napi_ok;
1111 }
1112 
GetInstanceData(napi_env env,void ** data)1113 napi_status GetInstanceData(napi_env env, void** data)
1114 {
1115     if (data) {
1116         *data = g_instanceData;
1117     }
1118 
1119     return napi_ok;
1120 }
1121 
1122 #else // __OHOS_PLATFORM__
1123 
SetInstanceData(napi_env env,void * data,napi_finalize finalizeCb,void * finalizeHint)1124 napi_status SetInstanceData(napi_env env, void* data, napi_finalize finalizeCb, void* finalizeHint)
1125 {
1126     return napi_set_instance_data(env, data, finalizeCb, finalizeHint);
1127 }
1128 
GetInstanceData(napi_env env,void ** data)1129 napi_status GetInstanceData(napi_env env, void** data)
1130 {
1131     return napi_get_instance_data(env, data);
1132 }
1133 
1134 #endif // __OHOS_PLATFORM__
1135 
1136