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 "LightJS.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_plugin/api/light_uid.h>
21 #include <scene_plugin/interface/intf_light.h>
22 #include <scene_plugin/interface/intf_scene.h>
23 using namespace NapiApi;
BaseLight(LightType lt)24 BaseLight::BaseLight(LightType lt) : NodeImpl(NodeImpl::NodeType::LIGHT), lightType_(lt) {}
RegisterEnums(NapiApi::Object exports)25 void BaseLight::RegisterEnums(NapiApi::Object exports)
26 {
27     napi_value v;
28     NapiApi::Object LightType(exports.GetEnv());
29 
30 #define DECL_ENUM(enu, x)                                     \
31     {                                                         \
32         napi_create_uint32(enu.GetEnv(), BaseLight::LightType::x, (&v)); \
33         enu.Set((#x), (v));                                 \
34     }
35     DECL_ENUM(LightType, DIRECTIONAL);
36     DECL_ENUM(LightType, POINT);
37     DECL_ENUM(LightType, SPOT);
38 #undef DECL_ENUM
39     exports.Set("LightType", LightType);
40 }
41 
Create(napi_env e,napi_callback_info i)42 void BaseLight::Create(napi_env e, napi_callback_info i)
43 {
44     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
45     if (!fromJs) {
46         // no arguments. so internal create.
47         // expecting caller to finish initialization
48         return;
49     }
50 
51     // java script call.. with arguments
52     NapiApi::Object scene = fromJs.Arg<0>();
53     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
54         CORE_LOG_F("INVALID SCENE!");
55     }
56     scene_ = { scene };
57     auto scn = GetNativeMeta<SCENE_NS::IScene>(scene);
58 
59     if (scn == nullptr) {
60         // hmm..
61         CORE_LOG_F("Invalid scene for LightJS!");
62         return;
63     }
64     // collect parameters
65     NapiApi::Value<BASE_NS::string> name;
66     NapiApi::Value<BASE_NS::string> path;
67     NapiApi::Object args = fromJs.Arg<1>();
68     if (auto prm = args.Get("name")) {
69         name = NapiApi::Value<BASE_NS::string>(e, prm);
70     }
71     if (auto prm = args.Get("path")) {
72         path = NapiApi::Value<BASE_NS::string>(e, prm);
73     }
74 
75     BASE_NS::string nodePath;
76 
77     if (path) {
78         // create using path
79         nodePath = path.valueOrDefault("");
80     } else if (name) {
81         // use the name as path (creates under root)
82         nodePath = name.valueOrDefault("");
83     } else {
84         // no name or path defined should this just fail?
85     }
86 
87     // Create actual camera object.
88     SCENE_NS::ILight::Ptr node;
89     ExecSyncTask([scn, nodePath, &node]() {
90         node = scn->CreateNode<SCENE_NS::ILight>(nodePath, true);
91         return META_NS::IAny::Ptr {};
92     });
93 
94     TrueRootObject* instance = GetThisRootObject(fromJs);
95 
96     instance->SetNativeObject(interface_pointer_cast<META_NS::IObject>(node), false);
97     node.reset();
98 
99     NapiApi::Object meJs(e, fromJs.This());
100     StoreJsObj(instance->GetNativeObject(), meJs);
101 
102     if (name) {
103         // set the name of the object. if we were given one
104         meJs.Set("name", name);
105     }
106 }
~BaseLight()107 BaseLight::~BaseLight() {}
Init(const char * class_name,napi_env env,napi_value exports,BASE_NS::vector<napi_property_descriptor> & np,napi_callback ctor)108 void BaseLight::Init(const char* class_name, napi_env env, napi_value exports,
109     BASE_NS::vector<napi_property_descriptor>& np, napi_callback ctor)
110 {
111     NodeImpl::GetPropertyDescs(np);
112 
113     np.push_back(TROGetProperty<float, BaseLight, &BaseLight::GetlightType>("lightType"));
114     np.push_back(TROGetSetProperty<Object, BaseLight, &BaseLight::GetColor, &BaseLight::SetColor>("color"));
115     np.push_back(TROGetSetProperty<float, BaseLight, &BaseLight::GetIntensity, &BaseLight::SetIntensity>("intensity"));
116     np.push_back(TROGetSetProperty<bool, BaseLight, &BaseLight::GetShadowEnabled, &BaseLight::SetShadowEnabled>(
117         "shadowEnabled"));
118     np.push_back(TROGetSetProperty<bool, BaseLight, &BaseLight::GetEnabled, &BaseLight::SetEnabled>("enabled"));
119 
120     napi_value func;
121     auto status = napi_define_class(env, class_name, NAPI_AUTO_LENGTH, ctor, nullptr, np.size(), np.data(), &func);
122 
123     NapiApi::MyInstanceState* mis;
124     napi_get_instance_data(env, (void**)&mis);
125     mis->StoreCtor(class_name, func);
126 }
Finalize(napi_env env,TrueRootObject * tro)127 void BaseLight::Finalize(napi_env env, TrueRootObject* tro)
128 {
129     tro->Finalize(env);
130 }
131 
GetInstanceImpl(uint32_t id)132 void* BaseLight::GetInstanceImpl(uint32_t id)
133 {
134     if (id == BaseLight::ID) {
135         return this;
136     }
137     return NodeImpl::GetInstanceImpl(id);
138 }
DisposeNative(TrueRootObject * tro)139 void BaseLight::DisposeNative(TrueRootObject* tro)
140 {
141     // do nothing for now..
142     LOG_F("BaseLight::DisposeNative");
143     colorProxy_.reset();
144     if (auto light = interface_pointer_cast<SCENE_NS::ILight>(tro->GetNativeObject())) {
145         // reset the native object refs
146         tro->SetNativeObject(nullptr, false);
147         tro->SetNativeObject(nullptr, true);
148 
149         ExecSyncTask([light = BASE_NS::move(light)]() mutable {
150             auto node = interface_pointer_cast<SCENE_NS::INode>(light);
151             if (node == nullptr) {
152                 return META_NS::IAny::Ptr {};
153             }
154             auto scene = node->GetScene();
155             if (scene == nullptr) {
156                 return META_NS::IAny::Ptr {};
157             }
158             scene->ReleaseNode(node);
159             return META_NS::IAny::Ptr {};
160         });
161     }
162     scene_.Reset();
163 }
GetlightType(NapiApi::FunctionContext<> & ctx)164 napi_value BaseLight::GetlightType(NapiApi::FunctionContext<>& ctx)
165 {
166     uint32_t type = -1; // return -1 if the object does not exist anymore
167     if (auto node = interface_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx))) {
168         type = lightType_;
169     }
170     napi_value value;
171     napi_status status = napi_create_uint32(ctx, type, &value);
172     return value;
173 }
174 
GetEnabled(NapiApi::FunctionContext<> & ctx)175 napi_value BaseLight::GetEnabled(NapiApi::FunctionContext<>& ctx)
176 {
177     bool enable = true;
178     auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
179     if (node) {
180         ExecSyncTask([node, &enable]() {
181             enable = node->Visible()->GetValue();
182             return META_NS::IAny::Ptr {};
183         });
184     }
185     napi_value value;
186     napi_status status = napi_get_boolean(ctx, enable, &value);
187     return value;
188 }
189 
SetEnabled(NapiApi::FunctionContext<bool> & ctx)190 void BaseLight::SetEnabled(NapiApi::FunctionContext<bool>& ctx)
191 {
192     bool enabled = ctx.Arg<0>();
193     auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
194     if (node) {
195         ExecSyncTask([node, enabled]() {
196             node->Visible()->SetValue(enabled);
197             return META_NS::IAny::Ptr {};
198         });
199     }
200 }
201 
GetColor(NapiApi::FunctionContext<> & ctx)202 napi_value BaseLight::GetColor(NapiApi::FunctionContext<>& ctx)
203 {
204     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
205     if (!node) {
206         return {};
207     }
208     if (colorProxy_ == nullptr) {
209         colorProxy_ = BASE_NS::make_unique<ColorProxy>(ctx, node->Color());
210     }
211     return colorProxy_->Value();
212 }
SetColor(NapiApi::FunctionContext<Object> & ctx)213 void BaseLight::SetColor(NapiApi::FunctionContext<Object>& ctx)
214 {
215     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
216     if (!node) {
217         return;
218     }
219     NapiApi::Object obj = ctx.Arg<0>();
220     if (colorProxy_ == nullptr) {
221         colorProxy_ = BASE_NS::make_unique<ColorProxy>(ctx, node->Color());
222     }
223     colorProxy_->SetValue(obj);
224 }
225 
GetShadowEnabled(NapiApi::FunctionContext<> & ctx)226 napi_value BaseLight::GetShadowEnabled(NapiApi::FunctionContext<>& ctx)
227 {
228     bool enable = true;
229     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
230     if (node) {
231         ExecSyncTask([node, &enable]() {
232             enable = node->ShadowEnabled()->GetValue();
233             return META_NS::IAny::Ptr {};
234         });
235     }
236     napi_value value;
237     napi_status status = napi_get_boolean(ctx, enable, &value);
238     return value;
239 }
SetShadowEnabled(NapiApi::FunctionContext<bool> & ctx)240 void BaseLight::SetShadowEnabled(NapiApi::FunctionContext<bool>& ctx)
241 {
242     bool enabled = ctx.Arg<0>();
243     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
244     if (node) {
245         ExecSyncTask([node, enabled]() {
246             node->ShadowEnabled()->SetValue(enabled);
247             return META_NS::IAny::Ptr {};
248         });
249     }
250 }
251 
GetIntensity(NapiApi::FunctionContext<> & ctx)252 napi_value BaseLight::GetIntensity(NapiApi::FunctionContext<>& ctx)
253 {
254     float intensity = 0.0f;
255     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
256     if (node) {
257         ExecSyncTask([node, &intensity]() {
258             intensity = node->Intensity()->GetValue();
259             return META_NS::IAny::Ptr {};
260         });
261     }
262     napi_value value;
263     napi_status status = napi_create_double(ctx, intensity, &value);
264     return value;
265 }
SetIntensity(NapiApi::FunctionContext<float> & ctx)266 void BaseLight::SetIntensity(NapiApi::FunctionContext<float>& ctx)
267 {
268     float intensity = ctx.Arg<0>();
269     auto node = interface_pointer_cast<SCENE_NS::ILight>(GetThisNativeObject(ctx));
270     if (node) {
271         ExecSyncTask([node, intensity]() {
272             node->Intensity()->SetValue(intensity);
273             return META_NS::IAny::Ptr {};
274         });
275     }
276 }
277 
SpotLightJS(napi_env e,napi_callback_info i)278 SpotLightJS::SpotLightJS(napi_env e, napi_callback_info i)
279     : BaseObject<SpotLightJS>(e, i), BaseLight(BaseLight::LightType::SPOT)
280 {
281     Create(e, i);
282     if (auto light = interface_pointer_cast<SCENE_NS::ILight>(GetNativeObject())) {
283         light->Type()->SetValue(SCENE_NS::ILight::SCENE_LIGHT_SPOT);
284     }
285 }
Init(napi_env env,napi_value exports)286 void SpotLightJS::Init(napi_env env, napi_value exports)
287 {
288     BASE_NS::vector<napi_property_descriptor> node_props;
289 
290     BaseLight::Init("SpotLight", env, exports, node_props, BaseObject::ctor<SpotLightJS>());
291 }
292 
GetInstanceImpl(uint32_t id)293 void* SpotLightJS::GetInstanceImpl(uint32_t id)
294 {
295     if (id == SpotLightJS::ID) {
296         return this;
297     }
298     return BaseLight::GetInstanceImpl(id);
299 }
DisposeNative()300 void SpotLightJS::DisposeNative()
301 {
302     BaseLight::DisposeNative(this);
303 }
Finalize(napi_env env)304 void SpotLightJS::Finalize(napi_env env)
305 {
306     BaseObject<SpotLightJS>::Finalize(env);
307 }
PointLightJS(napi_env e,napi_callback_info i)308 PointLightJS::PointLightJS(napi_env e, napi_callback_info i)
309     : BaseObject<PointLightJS>(e, i), BaseLight(BaseLight::LightType::POINT)
310 {
311     Create(e, i);
312     if (auto light = interface_pointer_cast<SCENE_NS::ILight>(GetNativeObject())) {
313         light->Type()->SetValue(SCENE_NS::ILight::SCENE_LIGHT_POINT);
314     }
315 }
GetInstanceImpl(uint32_t id)316 void* PointLightJS::GetInstanceImpl(uint32_t id)
317 {
318     if (id == PointLightJS::ID) {
319         return this;
320     }
321     return BaseLight::GetInstanceImpl(id);
322 }
DisposeNative()323 void PointLightJS::DisposeNative()
324 {
325     BaseLight::DisposeNative(this);
326 }
Finalize(napi_env env)327 void PointLightJS::Finalize(napi_env env)
328 {
329     BaseObject<PointLightJS>::Finalize(env);
330 }
Init(napi_env env,napi_value exports)331 void PointLightJS::Init(napi_env env, napi_value exports)
332 {
333     BASE_NS::vector<napi_property_descriptor> node_props;
334     BaseLight::Init("PointLight", env, exports, node_props, BaseObject::ctor<PointLightJS>());
335 }
336 
DirectionalLightJS(napi_env e,napi_callback_info i)337 DirectionalLightJS::DirectionalLightJS(napi_env e, napi_callback_info i)
338     : BaseObject<DirectionalLightJS>(e, i), BaseLight(BaseLight::LightType::DIRECTIONAL)
339 {
340     Create(e, i);
341     if (auto light = interface_pointer_cast<SCENE_NS::ILight>(GetNativeObject())) {
342         light->Type()->SetValue(SCENE_NS::ILight::SCENE_LIGHT_DIRECTIONAL);
343     }
344 }
GetInstanceImpl(uint32_t id)345 void* DirectionalLightJS::GetInstanceImpl(uint32_t id)
346 {
347     if (id == DirectionalLightJS::ID) {
348         return this;
349     }
350     return BaseLight::GetInstanceImpl(id);
351 }
DisposeNative()352 void DirectionalLightJS::DisposeNative()
353 {
354     BaseLight::DisposeNative(this);
355 }
Finalize(napi_env env)356 void DirectionalLightJS::Finalize(napi_env env)
357 {
358     BaseObject<DirectionalLightJS>::Finalize(env);
359 }
360 
Init(napi_env env,napi_value exports)361 void DirectionalLightJS::Init(napi_env env, napi_value exports)
362 {
363     BASE_NS::vector<napi_property_descriptor> node_props;
364     node_props.push_back(
365         GetSetProperty<float, DirectionalLightJS, &DirectionalLightJS::GetNear, &DirectionalLightJS::SetNear>(
366             "nearPlane"));
367     BaseLight::Init("DirectionalLight", env, exports, node_props, BaseObject::ctor<DirectionalLightJS>());
368 }
369 
GetNear(NapiApi::FunctionContext<> & ctx)370 napi_value DirectionalLightJS::GetNear(NapiApi::FunctionContext<>& ctx)
371 {
372     float fov = 0.0;
373     if (auto camera = interface_cast<SCENE_NS::ILight>(GetNativeObject())) {
374         ExecSyncTask([camera, &fov]() {
375             fov = 0.0;
376             if (camera) {
377                 fov = camera->NearPlane()->GetValue();
378             }
379             return META_NS::IAny::Ptr {};
380         });
381     }
382 
383     napi_value value;
384     napi_status status = napi_create_double(ctx, fov, &value);
385     return value;
386 }
387 
SetNear(NapiApi::FunctionContext<float> & ctx)388 void DirectionalLightJS::SetNear(NapiApi::FunctionContext<float>& ctx)
389 {
390     float fov = ctx.Arg<0>();
391     if (auto camera = interface_cast<SCENE_NS::ILight>(GetNativeObject())) {
392         ExecSyncTask([camera, fov]() {
393             camera->NearPlane()->SetValue(fov);
394             return META_NS::IAny::Ptr {};
395         });
396     }
397 }