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