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 }