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