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
16 #include "ToneMapJS.h"
17
18 #include <meta/api/make_callback.h>
19 #include <meta/interface/intf_task_queue.h>
20 #include <meta/interface/intf_task_queue_registry.h>
21 #include <meta/interface/property/property_events.h>
22 #include <scene/interface/intf_node.h>
23 #include <scene/interface/intf_postprocess.h>
24 #include <scene/interface/intf_scene.h>
25
26 #include <render/intf_render_context.h>
27
28 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
29 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
30 using namespace SCENE_NS;
ToNative(ToneMapJS::ToneMappingType typeI)31 SCENE_NS::TonemapType ToNative(ToneMapJS::ToneMappingType typeI)
32 {
33 SCENE_NS::TonemapType type;
34 switch (typeI) {
35 case ToneMapJS::ToneMappingType::ACES:
36 type = SCENE_NS::TonemapType::ACES;
37 break;
38 case ToneMapJS::ToneMappingType::ACES_2020:
39 type = SCENE_NS::TonemapType::ACES_2020;
40 break;
41 case ToneMapJS::ToneMappingType::FILMIC:
42 type = SCENE_NS::TonemapType::FILMIC;
43 break;
44 default:
45 // default from lowlev..
46 type = SCENE_NS::TonemapType::ACES;
47 break;
48 }
49 return type;
50 }
ToJs(SCENE_NS::TonemapType typeI)51 ToneMapJS::ToneMappingType ToJs(SCENE_NS::TonemapType typeI)
52 {
53 ToneMapJS::ToneMappingType type;
54 switch (typeI) {
55 case SCENE_NS::TonemapType::ACES:
56 type = ToneMapJS::ToneMappingType::ACES;
57 break;
58 case SCENE_NS::TonemapType::ACES_2020:
59 type = ToneMapJS::ToneMappingType::ACES_2020;
60 break;
61 case SCENE_NS::TonemapType::FILMIC:
62 type = ToneMapJS::ToneMappingType ::FILMIC;
63 break;
64 default:
65 // default from lowlev..
66 type = ToneMapJS::ToneMappingType ::ACES;
67 break;
68 }
69 return type;
70 }
71
ToNativeType(uint32_t typeI)72 SCENE_NS::TonemapType ToneMapJS::ToNativeType(uint32_t typeI)
73 {
74 return ToNative(static_cast<ToneMapJS::ToneMappingType>(typeI));
75 }
76
Init(napi_env env,napi_value exports)77 void ToneMapJS::Init(napi_env env, napi_value exports)
78 {
79 using namespace NapiApi;
80
81 BASE_NS::vector<napi_property_descriptor> node_props;
82 // clang-format off
83 node_props.emplace_back(GetSetProperty<uint32_t, ToneMapJS, &ToneMapJS::GetType, &ToneMapJS::SetType>("type"));
84 node_props.emplace_back(
85 GetSetProperty<float, ToneMapJS, &ToneMapJS::GetExposure, &ToneMapJS::SetExposure>("exposure"));
86 node_props.push_back(MakeTROMethod<NapiApi::FunctionContext<>, ToneMapJS, &ToneMapJS::Dispose>("destroy"));
87 // clang-format on
88
89 napi_value func;
90 auto status = napi_define_class(env, "ToneMappingSettings", NAPI_AUTO_LENGTH, BaseObject::ctor<ToneMapJS>(),
91 nullptr, node_props.size(), node_props.data(), &func);
92
93 NapiApi::MyInstanceState* mis;
94 NapiApi::MyInstanceState::GetInstance(env, (void**)&mis);
95 if (mis) {
96 mis->StoreCtor("ToneMappingSettings", func);
97 }
98
99 NapiApi::Object exp(env, exports);
100
101 napi_value eType, v;
102 napi_create_object(env, &eType);
103 #define DECL_ENUM(enu, x) \
104 napi_create_uint32(env, ToneMappingType::x, &v); \
105 napi_set_named_property(env, enu, #x, v);
106
107 DECL_ENUM(eType, ACES);
108 DECL_ENUM(eType, ACES_2020);
109 DECL_ENUM(eType, FILMIC);
110 #undef DECL_ENUM
111 exp.Set("ToneMappingType", eType);
112 }
113
Dispose(NapiApi::FunctionContext<> & ctx)114 napi_value ToneMapJS::Dispose(NapiApi::FunctionContext<>& ctx)
115 {
116 LOG_V("ToneMapJS::Dispose");
117 DisposeNative(nullptr);
118 return {};
119 }
DisposeNative(void *)120 void ToneMapJS::DisposeNative(void*)
121 {
122 if (!disposed_) {
123 disposed_ = true;
124 LOG_V("ToneMapJS::DisposeNative");
125 UnsetNativeObject();
126 }
127 }
UnbindFromNative()128 void ToneMapJS::UnbindFromNative()
129 {
130 // We don't use a property proxy, so update members manually.
131 if (auto toneMap = GetNativeObject<SCENE_NS::ITonemap>()) {
132 type_ = ToJs(toneMap->Type()->GetValue());
133 exposure_ = toneMap->Exposure()->GetValue();
134 }
135 UnsetNativeObject();
136 }
137
BindToNative(SCENE_NS::ITonemap::Ptr native)138 void ToneMapJS::BindToNative(SCENE_NS::ITonemap::Ptr native)
139 {
140 SetNativeObject(interface_pointer_cast<META_NS::IObject>(native), PtrType::WEAK);
141 if (auto toneMap = GetNativeObject<SCENE_NS::ITonemap>()) {
142 toneMap->Type()->SetValue(ToNative(type_));
143 toneMap->Exposure()->SetValue(exposure_);
144 }
145 }
146
GetInstanceImpl(uint32_t id)147 void* ToneMapJS::GetInstanceImpl(uint32_t id)
148 {
149 if (id == ToneMapJS::ID)
150 return this;
151 return nullptr;
152 }
Finalize(napi_env env)153 void ToneMapJS::Finalize(napi_env env)
154 {
155 DisposeNative(nullptr);
156 BaseObject::Finalize(env);
157 }
158
ToneMapJS(napi_env e,napi_callback_info i)159 ToneMapJS::ToneMapJS(napi_env e, napi_callback_info i)
160 : BaseObject(e, i), type_(DEFAULT_TYPE), exposure_(DEFAULT_EXPOSURE)
161 {
162 LOG_V("ToneMapJS ++");
163 auto tonemap = GetNativeObject<SCENE_NS::ITonemap>();
164 if (!tonemap) {
165 LOG_E("Cannot finish creating a tonemap: Native tonemap object missing");
166 assert(false);
167 return;
168 }
169
170 // We accept 0 and 1 arg calls. If we get 0, do nothing so original tonemap stays unchanged.
171 NapiApi::FunctionContext<NapiApi::Object> ctx(e, i);
172 if (!ctx) {
173 if (ctx.ArgCount() != 0) {
174 LOG_E("Cannot finish creating a tonemap: Invalid args given");
175 assert(false);
176 }
177 return;
178 }
179
180 NapiApi::Object toneMapArgs = ctx.Arg<0>();
181 exposure_ = toneMapArgs.Get<float>("exposure").valueOrDefault(exposure_);
182 type_ = static_cast<ToneMappingType>(toneMapArgs.Get<uint32_t>("type").valueOrDefault(type_));
183 tonemap->Type()->SetValue(ToNative(type_));
184 tonemap->Exposure()->SetValue(exposure_);
185 tonemap->Enabled()->SetValue(true);
186 }
187
~ToneMapJS()188 ToneMapJS::~ToneMapJS()
189 {
190 LOG_V("ToneMapJS --");
191 DisposeNative(nullptr);
192 if (!GetNativeObject()) {
193 return;
194 }
195 }
196
GetType(NapiApi::FunctionContext<> & ctx)197 napi_value ToneMapJS::GetType(NapiApi::FunctionContext<>& ctx)
198 {
199 if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
200 type_ = ToJs(toneMap->Type()->GetValue());
201 }
202
203 return ctx.GetNumber(static_cast<uint32_t>(type_));
204 }
205
SetType(NapiApi::FunctionContext<uint32_t> & ctx)206 void ToneMapJS::SetType(NapiApi::FunctionContext<uint32_t>& ctx)
207 {
208 const auto nativeType = ToNativeType(ctx.Arg<0>());
209 type_ = ToJs(nativeType);
210
211 if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
212 toneMap->Type()->SetValue(nativeType);
213 }
214 }
215
GetExposure(NapiApi::FunctionContext<> & ctx)216 napi_value ToneMapJS::GetExposure(NapiApi::FunctionContext<>& ctx)
217 {
218 if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
219 exposure_ = toneMap->Exposure()->GetValue();
220 }
221
222 return ctx.GetNumber(exposure_);
223 }
224
SetExposure(NapiApi::FunctionContext<float> & ctx)225 void ToneMapJS::SetExposure(NapiApi::FunctionContext<float>& ctx)
226 {
227 exposure_ = ctx.Arg<0>();
228 if (auto toneMap = interface_cast<SCENE_NS::ITonemap>(GetNativeObject())) {
229 toneMap->Exposure()->SetValue(exposure_);
230 }
231 }
232