• 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 "EnvironmentJS.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 <meta/interface/property/property_events.h>
21 #include <scene/interface/intf_node.h>
22 #include <scene/interface/intf_scene.h>
23 
24 #include <render/intf_render_context.h>
25 
26 #include "SceneJS.h"
27 using namespace SCENE_NS;
28 
Init(napi_env env,napi_value exports)29 void EnvironmentJS::Init(napi_env env, napi_value exports)
30 {
31     using namespace NapiApi;
32 
33     BASE_NS::vector<napi_property_descriptor> node_props;
34     SceneResourceImpl::GetPropertyDescs(node_props);
35     // clang-format off
36 
37     node_props.emplace_back(GetSetProperty<uint32_t, EnvironmentJS, &EnvironmentJS::GetBackgroundType,
38         &EnvironmentJS::SetBackgroundType>("backgroundType"));
39     node_props.emplace_back(GetSetProperty<Object, EnvironmentJS, &EnvironmentJS::GetEnvironmentImage,
40         &EnvironmentJS::SetEnvironmentImage>("environmentImage"));
41     node_props.emplace_back(GetSetProperty<Object, EnvironmentJS, &EnvironmentJS::GetRadianceImage,
42         &EnvironmentJS::SetRadianceImage>("radianceImage"));
43     node_props.emplace_back(GetSetProperty<NapiApi::Array, EnvironmentJS, &EnvironmentJS::GetIrradianceCoefficients,
44         &EnvironmentJS::SetIrradianceCoefficients>("irradianceCoefficients"));
45     node_props.emplace_back(GetSetProperty<Object, EnvironmentJS, &EnvironmentJS::GetIndirectDiffuseFactor,
46         &EnvironmentJS::SetIndirectDiffuseFactor>("indirectDiffuseFactor"));
47     node_props.emplace_back(GetSetProperty<Object, EnvironmentJS, &EnvironmentJS::GetIndirectSpecularFactor,
48         &EnvironmentJS::SetIndirectSpecularFactor>("indirectSpecularFactor"));
49     node_props.emplace_back(GetSetProperty<Object, EnvironmentJS, &EnvironmentJS::GetEnvironmentMapFactor,
50         &EnvironmentJS::SetEnvironmentMapFactor>("environmentMapFactor"));
51 
52     // clang-format on
53 
54     napi_value func;
55     auto status = napi_define_class(env, "Environment", NAPI_AUTO_LENGTH, BaseObject::ctor<EnvironmentJS>(), nullptr,
56         node_props.size(), node_props.data(), &func);
57 
58     NapiApi::MyInstanceState* mis;
59     GetInstanceData(env, (void**)&mis);
60     mis->StoreCtor("Environment", func);
61 
62     NapiApi::Object exp(env, exports);
63 
64     napi_value eType;
65     napi_value v;
66     napi_create_object(env, &eType);
67 #define DECL_ENUM(enu, x)                                      \
68     napi_create_uint32(env, EnvironmentBackgroundType::x, &v); \
69     napi_set_named_property(env, enu, #x, v);
70 
71     DECL_ENUM(eType, BACKGROUND_NONE);
72     DECL_ENUM(eType, BACKGROUND_IMAGE);
73     DECL_ENUM(eType, BACKGROUND_CUBEMAP);
74     DECL_ENUM(eType, BACKGROUND_EQUIRECTANGULAR);
75 #undef DECL_ENUM
76     exp.Set("EnvironmentBackgroundType", eType);
77 }
78 
DisposeNative(void * scene)79 void EnvironmentJS::DisposeNative(void* scene)
80 {
81     if (scene == nullptr) {
82         if (!disposed_) {
83             LOG_F("EnvironmentJS::DisposeNative but argument NULL");
84         }
85         return;
86     }
87     if (!disposed_) {
88         LOG_V("EnvironmentJS::DisposeNative");
89         disposed_ = true;
90         SceneJS* sceneJS { static_cast<SceneJS*>(scene) };
91         if (sceneJS) {
92             sceneJS->ReleaseStrongDispose(reinterpret_cast<uintptr_t>(&scene_));
93         }
94         diffuseFactor_.reset();
95         specularFactor_.reset();
96         environmentFactor_.reset();
97         if (auto env = interface_pointer_cast<IEnvironment>(GetNativeObject())) {
98             // reset the native object refs
99             SetNativeObject(nullptr, false);
100             SetNativeObject(nullptr, true);
101 
102             // if we still have javascript scene reference, detach from it.
103             // (if not, then scene has died and we are detaching already)
104             NapiApi::Object sceneJs = scene_.GetObject();
105             if (!sceneJs) {
106                 LOG_E("sceneJs is nullptr");
107                 return;
108             }
109             napi_value null;
110             napi_get_null(sceneJs.GetEnv(), &null);
111             sceneJs.Set("environment", null);
112             if (sceneJS) {
113                 IScene::Ptr s = interface_pointer_cast<IScene>(sceneJS->GetNativeObject());
114                 if (s) {
115                     env->EnvironmentImage()->SetValue(nullptr);
116                     env->RadianceImage()->SetValue(nullptr);
117                     env.reset();
118                     s.reset();
119                 }
120             }
121         }
122     }
123     scene_.Reset();
124 }
GetInstanceImpl(uint32_t id)125 void* EnvironmentJS::GetInstanceImpl(uint32_t id)
126 {
127     if (id == EnvironmentJS::ID)
128         return this;
129     return SceneResourceImpl::GetInstanceImpl(id);
130 }
Finalize(napi_env env)131 void EnvironmentJS::Finalize(napi_env env)
132 {
133     DisposeNative(GetJsWrapper<SceneJS>(scene_.GetObject()));
134     BaseObject<EnvironmentJS>::Finalize(env);
135 }
136 
EnvironmentJS(napi_env e,napi_callback_info i)137 EnvironmentJS::EnvironmentJS(napi_env e, napi_callback_info i)
138     : BaseObject<EnvironmentJS>(e, i), SceneResourceImpl(SceneResourceImpl::ENVIRONMENT)
139 {
140     LOG_V("EnvironmentJS ++");
141     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
142     if (!fromJs) {
143         // no arguments. so internal create.
144         // expecting caller to finish
145         return;
146     }
147 
148     scene_ = fromJs.Arg<0>().valueOrDefault();
149     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
150         LOG_F("INVALID SCENE!");
151     }
152 
153     NapiApi::Object meJs(fromJs.This());
154     if (auto sceneJS = GetJsWrapper<SceneJS>(scene_.GetObject())) {
155         sceneJS->StrongDisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
156     }
157     IScene::Ptr scene;
158     if (auto* tro = scene_.GetObject().Native<TrueRootObject>()) {
159         scene = interface_pointer_cast<IScene>(tro->GetNativeObject());
160     }
161 
162     NapiApi::Value<BASE_NS::string> name;
163     NapiApi::Object args = fromJs.Arg<1>();
164     if (auto prm = args.Get("name")) {
165         name = NapiApi::Value<BASE_NS::string>(e, prm);
166     }
167 
168     BASE_NS::string nameS = name;
169     if (nameS.empty()) {
170         // create "unique" name
171         nameS = BASE_NS::to_string(reinterpret_cast<uint64_t>(this));
172     }
173     IEnvironment::Ptr env = GetNativeMeta<IEnvironment>(meJs);
174     // Construct native object (if needed)
175 
176     if (!env) {
177         BASE_NS::string_view n = nameS; /*nodepath actually*/
178         if (scene) {
179             env = scene->CreateObject<SCENE_NS::IEnvironment>(SCENE_NS::ClassId::Environment).GetResult();
180         }
181     }
182 
183     // process constructor args
184     SetNativeObject(interface_pointer_cast<META_NS::IObject>(env), true);
185     StoreJsObj(interface_pointer_cast<META_NS::IObject>(env), meJs);
186     env.reset();
187 
188     if (name.IsDefined()) {
189         // set the name of the object. if we were given one
190         meJs.Set("name", name);
191     }
192 }
193 
~EnvironmentJS()194 EnvironmentJS::~EnvironmentJS()
195 {
196     LOG_V("EnvironmentJS --");
197     DisposeNative(nullptr);
198     if (!GetNativeObject()) {
199         return;
200     }
201 }
202 
GetBackgroundType(NapiApi::FunctionContext<> & ctx)203 napi_value EnvironmentJS::GetBackgroundType(NapiApi::FunctionContext<>& ctx)
204 {
205     if (!validateSceneRef()) {
206         return ctx.GetUndefined();
207     }
208     uint32_t typeI = 0;
209     if (auto env = interface_cast<IEnvironment>(GetNativeObject())) {
210         typeI = uint32_t(env->Background()->GetValue());
211     }
212     return ctx.GetNumber(static_cast<uint32_t>(typeI));
213 }
214 
SetBackgroundType(NapiApi::FunctionContext<uint32_t> & ctx)215 void EnvironmentJS::SetBackgroundType(NapiApi::FunctionContext<uint32_t>& ctx)
216 {
217     if (!validateSceneRef()) {
218         return;
219     }
220 
221     if (auto env = interface_cast<IEnvironment>(GetNativeObject())) {
222         uint32_t typeI = ctx.Arg<0>();
223         auto typeE = static_cast<EnvironmentBackgroundType>(typeI);
224         EnvBackgroundType type;
225         switch (typeE) {
226             case EnvironmentBackgroundType::BACKGROUND_NONE:
227                 type = EnvBackgroundType::NONE;
228                 break;
229             case EnvironmentBackgroundType::BACKGROUND_IMAGE:
230                 type = EnvBackgroundType::IMAGE;
231                 break;
232             case EnvironmentBackgroundType::BACKGROUND_CUBEMAP:
233                 type = EnvBackgroundType::CUBEMAP;
234                 break;
235             case EnvironmentBackgroundType::BACKGROUND_EQUIRECTANGULAR:
236                 type = EnvBackgroundType::EQUIRECTANGULAR;
237                 break;
238             default:
239                 type = EnvBackgroundType::NONE;
240                 break;
241         }
242         env->Background()->SetValue(type);
243     }
244 }
GetEnvironmentImage(NapiApi::FunctionContext<> & ctx)245 napi_value EnvironmentJS::GetEnvironmentImage(NapiApi::FunctionContext<>& ctx)
246 {
247     if (!validateSceneRef()) {
248         return ctx.GetUndefined();
249     }
250 
251     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
252         SCENE_NS::IBitmap::Ptr image = environment->EnvironmentImage()->GetValue();
253         auto obj = interface_pointer_cast<META_NS::IObject>(image);
254 
255         if (auto cached = FetchJsObj(obj)) {
256             return cached.ToNapiValue();
257         }
258 
259         napi_value args[] = { scene_.GetValue(), NapiApi::Object(ctx.GetEnv()).ToNapiValue() };
260         return CreateFromNativeInstance(ctx.Env(), obj, false, BASE_NS::countof(args), args).ToNapiValue();
261     }
262     return ctx.GetNull();
263 }
264 
SetEnvironmentImage(NapiApi::FunctionContext<NapiApi::Object> & ctx)265 void EnvironmentJS::SetEnvironmentImage(NapiApi::FunctionContext<NapiApi::Object>& ctx)
266 {
267     if (!validateSceneRef()) {
268         return;
269     }
270     NapiApi::Object imageJS = ctx.Arg<0>();
271     SCENE_NS::IBitmap::Ptr image;
272     if (auto nat = imageJS.Native<TrueRootObject>()) {
273         image = interface_pointer_cast<SCENE_NS::IBitmap>(nat->GetNativeObject());
274     }
275     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
276         environment->EnvironmentImage()->SetValue(image);
277     }
278 }
279 
GetRadianceImage(NapiApi::FunctionContext<> & ctx)280 napi_value EnvironmentJS::GetRadianceImage(NapiApi::FunctionContext<>& ctx)
281 {
282     if (!validateSceneRef()) {
283         return ctx.GetUndefined();
284     }
285 
286     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
287         SCENE_NS::IBitmap::Ptr image = environment->RadianceImage()->GetValue();
288         auto obj = interface_pointer_cast<META_NS::IObject>(image);
289 
290         if (auto cached = FetchJsObj(obj)) {
291             return cached.ToNapiValue();
292         }
293 
294         napi_value args[] = { scene_.GetValue(), NapiApi::Object(ctx.GetEnv()).ToNapiValue() };
295         return CreateFromNativeInstance(ctx.GetEnv(), obj, false, BASE_NS::countof(args), args).ToNapiValue();
296     }
297     return ctx.GetNull();
298 }
299 
SetRadianceImage(NapiApi::FunctionContext<NapiApi::Object> & ctx)300 void EnvironmentJS::SetRadianceImage(NapiApi::FunctionContext<NapiApi::Object>& ctx)
301 {
302     if (!validateSceneRef()) {
303         return;
304     }
305 
306     NapiApi::Object imageJS = ctx.Arg<0>();
307     SCENE_NS::IBitmap::Ptr image;
308     if (auto nat = imageJS.Native<TrueRootObject>()) {
309         image = interface_pointer_cast<SCENE_NS::IBitmap>(nat->GetNativeObject());
310     }
311     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
312         environment->RadianceImage()->SetValue(image);
313     }
314 }
GetIrradianceCoefficients(NapiApi::FunctionContext<> & ctx)315 napi_value EnvironmentJS::GetIrradianceCoefficients(NapiApi::FunctionContext<>& ctx)
316 {
317     if (!validateSceneRef()) {
318         return ctx.GetUndefined();
319     }
320     BASE_NS::vector<BASE_NS::Math::Vec3> coeffs;
321     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
322         coeffs = environment->IrradianceCoefficients()->GetValue();
323     }
324     NapiApi::Env env(ctx.Env());
325     NapiApi::Array res(env, 9); // 9: parm
326     size_t index = 0;
327     for (auto& v : coeffs) {
328         NapiApi::Object vec(env);
329         vec.Set("x", NapiApi::Value<float>(env, v.x));
330         vec.Set("y", NapiApi::Value<float>(env, v.y));
331         vec.Set("z", NapiApi::Value<float>(env, v.z));
332         res.Set(index++, vec);
333     }
334     return res;
335 }
SetIrradianceCoefficients(NapiApi::FunctionContext<NapiApi::Array> & ctx)336 void EnvironmentJS::SetIrradianceCoefficients(NapiApi::FunctionContext<NapiApi::Array>& ctx)
337 {
338     if (!validateSceneRef()) {
339         return;
340     }
341 
342     NapiApi::Array coeffJS = ctx.Arg<0>();
343     if (coeffJS.Count() != 9) { // 9: size
344         // not enough elements in array
345         return;
346     }
347     BASE_NS::vector<BASE_NS::Math::Vec3> coeffs;
348     for (auto i = 0; i < coeffJS.Count(); i++) {
349         NapiApi::Object obj = coeffJS.Get<NapiApi::Object>(i);
350         if (!obj) {
351             // not an object in array
352             return;
353         }
354         auto x = obj.Get<float>("x");
355         auto y = obj.Get<float>("y");
356         auto z = obj.Get<float>("z");
357         if (!x || !y || !z) {
358             // invalid kind of object.
359             return;
360         }
361         coeffs.emplace_back((float)x, (float)y, (float)z);
362     }
363 
364     if (auto environment = interface_cast<SCENE_NS::IEnvironment>(GetNativeObject())) {
365         environment->IrradianceCoefficients()->SetValue(coeffs);
366     }
367 }
368 
GetIndirectDiffuseFactor(NapiApi::FunctionContext<> & ctx)369 napi_value EnvironmentJS::GetIndirectDiffuseFactor(NapiApi::FunctionContext<>& ctx)
370 {
371     if (!validateSceneRef()) {
372         return ctx.GetUndefined();
373     }
374 
375     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
376     if (!node) {
377         return ctx.GetUndefined();
378     }
379     if (diffuseFactor_ == nullptr) {
380         diffuseFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->IndirectDiffuseFactor());
381     }
382     return diffuseFactor_->Value();
383 }
384 
SetIndirectDiffuseFactor(NapiApi::FunctionContext<NapiApi::Object> & ctx)385 void EnvironmentJS::SetIndirectDiffuseFactor(NapiApi::FunctionContext<NapiApi::Object>& ctx)
386 {
387     if (!validateSceneRef()) {
388         return;
389     }
390     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
391     if (!node) {
392         return;
393     }
394     NapiApi::Object obj = ctx.Arg<0>();
395     if (diffuseFactor_ == nullptr) {
396         diffuseFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->IndirectDiffuseFactor());
397     }
398     diffuseFactor_->SetValue(obj);
399 }
400 
GetIndirectSpecularFactor(NapiApi::FunctionContext<> & ctx)401 napi_value EnvironmentJS::GetIndirectSpecularFactor(NapiApi::FunctionContext<>& ctx)
402 {
403     if (!validateSceneRef()) {
404         return ctx.GetUndefined();
405     }
406     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
407     if (!node) {
408         return ctx.GetUndefined();
409     }
410     if (specularFactor_ == nullptr) {
411         specularFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->IndirectSpecularFactor());
412     }
413     return specularFactor_->Value();
414 }
415 
SetIndirectSpecularFactor(NapiApi::FunctionContext<NapiApi::Object> & ctx)416 void EnvironmentJS::SetIndirectSpecularFactor(NapiApi::FunctionContext<NapiApi::Object>& ctx)
417 {
418     if (!validateSceneRef()) {
419         return;
420     }
421     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
422     if (!node) {
423         return;
424     }
425     NapiApi::Object obj = ctx.Arg<0>();
426     if (specularFactor_ == nullptr) {
427         specularFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->IndirectSpecularFactor());
428     }
429     specularFactor_->SetValue(obj);
430 }
431 
GetEnvironmentMapFactor(NapiApi::FunctionContext<> & ctx)432 napi_value EnvironmentJS::GetEnvironmentMapFactor(NapiApi::FunctionContext<>& ctx)
433 {
434     if (!validateSceneRef()) {
435         return ctx.GetUndefined();
436     }
437     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
438     if (!node) {
439         return ctx.GetUndefined();
440     }
441     if (environmentFactor_ == nullptr) {
442         environmentFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->EnvMapFactor());
443     }
444     return environmentFactor_->Value();
445 }
446 
SetEnvironmentMapFactor(NapiApi::FunctionContext<NapiApi::Object> & ctx)447 void EnvironmentJS::SetEnvironmentMapFactor(NapiApi::FunctionContext<NapiApi::Object>& ctx)
448 {
449     if (!validateSceneRef()) {
450         return;
451     }
452     auto node = interface_pointer_cast<SCENE_NS::IEnvironment>(GetThisNativeObject(ctx));
453     if (!node) {
454         return;
455     }
456     NapiApi::Object obj = ctx.Arg<0>();
457     if (environmentFactor_ == nullptr) {
458         environmentFactor_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), node->EnvMapFactor());
459     }
460     environmentFactor_->SetValue(obj);
461 }
462