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