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 "ToneMapJS.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_plugin/api/camera.h> //for the classid...
22 #include <scene_plugin/api/node_uid.h>
23 #include <scene_plugin/interface/intf_ecs_scene.h>
24 #include <scene_plugin/interface/intf_node.h>
25 #include <scene_plugin/interface/intf_postprocess.h>
26 #include <scene_plugin/interface/intf_scene.h>
27 
28 #include <render/intf_render_context.h>
29 
30 #include "PostProcJS.h"
31 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
32 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
33 using namespace SCENE_NS;
ConvertTo(ToneMapJS::ToneMappingType typeI)34 SCENE_NS::ITonemap::TonemapType ConvertTo(ToneMapJS::ToneMappingType typeI)
35 {
36     SCENE_NS::ITonemap::TonemapType type;
37     switch (typeI) {
38         case ToneMapJS::ToneMappingType::ACES:
39             type = SCENE_NS::ITonemap::TonemapType::ACES;
40             break;
41         case ToneMapJS::ToneMappingType::ACES_2020:
42             type = SCENE_NS::ITonemap::TonemapType::ACES_2020;
43             break;
44         case ToneMapJS::ToneMappingType::FILMIC:
45             type = SCENE_NS::ITonemap::TonemapType::FILMIC;
46             break;
47         default:
48             // default from lowlev..
49             type = ITonemap::TonemapType::ACES;
50             break;
51     }
52     return type;
53 }
ConvertFrom(SCENE_NS::ITonemap::TonemapType typeI)54 ToneMapJS::ToneMappingType ConvertFrom(SCENE_NS::ITonemap::TonemapType typeI)
55 {
56     ToneMapJS::ToneMappingType type;
57     switch (typeI) {
58         case SCENE_NS::ITonemap::TonemapType::ACES:
59             type = ToneMapJS::ToneMappingType::ACES;
60             break;
61         case SCENE_NS::ITonemap::TonemapType::ACES_2020:
62             type = ToneMapJS::ToneMappingType::ACES_2020;
63             break;
64         case SCENE_NS::ITonemap::TonemapType::FILMIC:
65             type = ToneMapJS::ToneMappingType ::FILMIC;
66             break;
67         default:
68             // default from lowlev..
69             type = ToneMapJS::ToneMappingType ::ACES;
70             break;
71     }
72     return type;
73 }
74 
ConvertTo(uint32_t typeI)75 SCENE_NS::ITonemap::TonemapType ConvertTo(uint32_t typeI)
76 {
77     return ConvertTo(static_cast<ToneMapJS::ToneMappingType>(typeI));
78 }
Init(napi_env env,napi_value exports)79 void ToneMapJS::Init(napi_env env, napi_value exports)
80 {
81     using namespace NapiApi;
82 
83     BASE_NS::vector<napi_property_descriptor> node_props;
84     // clang-format off
85     node_props.emplace_back(GetSetProperty<uint32_t, ToneMapJS, &ToneMapJS::GetType, &ToneMapJS::SetType>("type"));
86     node_props.emplace_back(GetSetProperty<float, ToneMapJS, &ToneMapJS::GetExposure,
87         &ToneMapJS::SetExposure>("exposure"));
88     node_props.push_back(MakeTROMethod<NapiApi::FunctionContext<>, ToneMapJS, &ToneMapJS::Dispose>("destroy"));
89     // clang-format on
90 
91     napi_value func;
92     auto status = napi_define_class(env, "ToneMappingSettings", NAPI_AUTO_LENGTH, BaseObject::ctor<ToneMapJS>(),
93         nullptr, node_props.size(), node_props.data(), &func);
94 
95     NapiApi::MyInstanceState* mis;
96     napi_get_instance_data(env, (void**)&mis);
97     mis->StoreCtor("ToneMappingSettings", func);
98 
99     NapiApi::Object exp(env, exports);
100 
101     napi_value eType;
102     napi_value v;
103     napi_create_object(env, &eType);
104 #define DECL_ENUM(enu, x)                            \
105     napi_create_uint32(env, ToneMappingType::x, &v); \
106     napi_set_named_property(env, enu, #x, v);
107 
108     DECL_ENUM(eType, ACES);
109     DECL_ENUM(eType, ACES_2020);
110     DECL_ENUM(eType, FILMIC);
111 #undef DECL_ENUM
112     exp.Set("ToneMappingType", eType);
113 }
114 
Dispose(NapiApi::FunctionContext<> & ctx)115 napi_value ToneMapJS::Dispose(NapiApi::FunctionContext<>& ctx)
116 {
117     LOG_F("ToneMapJS::Dispose");
118     DisposeNative();
119     return {};
120 }
DisposeNative()121 void ToneMapJS::DisposeNative()
122 {
123     if (!disposed_) {
124         disposed_ = true;
125         LOG_F("ToneMapJS::DisposeNative");
126         if (auto tmp = interface_pointer_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
127             // reset the native object refs
128             SetNativeObject(nullptr, false);
129             SetNativeObject(nullptr, true);
130 
131             ExecSyncTask([scn = BASE_NS::move(tmp)]() { return META_NS::IAny::Ptr {}; });
132         }
133     }
134 }
GetInstanceImpl(uint32_t id)135 void* ToneMapJS::GetInstanceImpl(uint32_t id)
136 {
137     if (id == ToneMapJS::ID) {
138         return this;
139     }
140     return nullptr;
141 }
Finalize(napi_env env)142 void ToneMapJS::Finalize(napi_env env)
143 {
144     // hmm.. do i need to do something BEFORE the object gets deleted..
145     DisposeNative();
146     BaseObject<ToneMapJS>::Finalize(env);
147 }
148 
ToneMapJS(napi_env e,napi_callback_info i)149 ToneMapJS::ToneMapJS(napi_env e, napi_callback_info i) : BaseObject<ToneMapJS>(e, i)
150 {
151     LOG_F("ToneMapJS ++");
152     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
153     if (!fromJs) {
154         // no arguments. so internal create.
155         // expecting caller to finish
156         return;
157     }
158     // postprocess that we bind to..
159     NapiApi::Object postProcJS = fromJs.Arg<0>();
160     auto postproc = GetNativeMeta<SCENE_NS::IPostProcess>(postProcJS);
161     NapiApi::Object toneMapArgs = fromJs.Arg<1>();
162     // now, based on parameters, initialize the object
163     // so it is a tonemap
164     float exposure = toneMapArgs.Get<float>("exposure").valueOrDefault(0.7);
165     SCENE_NS::ITonemap::TonemapType type =
166         ConvertTo(toneMapArgs.Get<uint32_t>("type").valueOrDefault(ToneMappingType::ACES));
167 
168     auto tonemap = GetNativeObjectParam<SCENE_NS::ITonemap>(toneMapArgs);
169 
170     ExecSyncTask([&tonemap, exposure, type, postproc]() -> META_NS::IAny::Ptr {
171         if (!tonemap) {
172             tonemap = META_NS::GetObjectRegistry().Create<SCENE_NS::ITonemap>(SCENE_NS::ClassId::Tonemap);
173         }
174         tonemap->Type()->SetValue(type);
175         tonemap->Exposure()->SetValue(exposure);
176         tonemap->Enabled()->SetValue(true);
177         postproc->Tonemap()->SetValue(tonemap);
178         return {};
179     });
180     auto obj = interface_pointer_cast<META_NS::IObject>(tonemap);
181     // process constructor args..
182     NapiApi::Object meJs(e, fromJs.This());
183     // weak ref, due to the ToneMap class being owned by the postprocess.
184     SetNativeObject(obj, false);
185     StoreJsObj(obj, meJs);
186 }
187 
~ToneMapJS()188 ToneMapJS::~ToneMapJS()
189 {
190     LOG_F("ToneMapJS --");
191     DisposeNative();
192     if (!GetNativeObject()) {
193         return;
194     }
195 }
196 
GetType(NapiApi::FunctionContext<> & ctx)197 napi_value ToneMapJS::GetType(NapiApi::FunctionContext<>& ctx)
198 {
199     SCENE_NS::ITonemap::TonemapType type = SCENE_NS::ITonemap::TonemapType::ACES; // default
200     if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
201         ExecSyncTask([toneMap, &type]() {
202             type = toneMap->Type()->GetValue();
203             return META_NS::IAny::Ptr {};
204         });
205     }
206 
207     auto typeI = ConvertFrom(type);
208     napi_value value;
209     napi_status status = napi_create_uint32(ctx, static_cast<uint32_t>(typeI), &value);
210     return value;
211 }
SetType(NapiApi::FunctionContext<uint32_t> & ctx)212 void ToneMapJS::SetType(NapiApi::FunctionContext<uint32_t>& ctx)
213 {
214     auto type = ConvertTo(ctx.Arg<0>());
215 
216     if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
217         ExecSyncTask([toneMap, type]() {
218             toneMap->Type()->SetValue(type);
219             return META_NS::IAny::Ptr {};
220         });
221     }
222 }
223 
GetExposure(NapiApi::FunctionContext<> & ctx)224 napi_value ToneMapJS::GetExposure(NapiApi::FunctionContext<>& ctx)
225 {
226     float exp = 0.0;
227     if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
228         ExecSyncTask([toneMap, &exp]() {
229             exp = toneMap->Exposure()->GetValue();
230             return META_NS::IAny::Ptr {};
231         });
232     }
233 
234     napi_value value;
235     napi_status status = napi_create_double(ctx, exp, &value);
236     return value;
237 }
238 
SetExposure(NapiApi::FunctionContext<float> & ctx)239 void ToneMapJS::SetExposure(NapiApi::FunctionContext<float>& ctx)
240 {
241     float exp = ctx.Arg<0>();
242     if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
243         ExecSyncTask([toneMap, exp]() {
244             toneMap->Exposure()->SetValue(exp);
245             return META_NS::IAny::Ptr {};
246         });
247     }
248 }
249