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" 31using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>; 32using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>; 33using namespace SCENE_NS; 34SCENE_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} 54ToneMapJS::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 75SCENE_NS::ITonemap::TonemapType ConvertTo(uint32_t typeI) 76{ 77 return ConvertTo(static_cast<ToneMapJS::ToneMappingType>(typeI)); 78} 79void 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 115napi_value ToneMapJS::Dispose(NapiApi::FunctionContext<>& ctx) 116{ 117 LOG_F("ToneMapJS::Dispose"); 118 DisposeNative(); 119 return {}; 120} 121void 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} 135void* ToneMapJS::GetInstanceImpl(uint32_t id) 136{ 137 if (id == ToneMapJS::ID) { 138 return this; 139 } 140 return nullptr; 141} 142void 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 149ToneMapJS::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 188ToneMapJS::~ToneMapJS() 189{ 190 LOG_F("ToneMapJS --"); 191 DisposeNative(); 192 if (!GetNativeObject()) { 193 return; 194 } 195} 196 197napi_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} 212void 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 224napi_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 239void 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