/* * Copyright (C) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "PostProcJS.h" #include #include #include #include #include //for the classid... #include #include #include #include #include #include "CameraJS.h" using IntfPtr = BASE_NS::shared_ptr; using IntfWeakPtr = BASE_NS::weak_ptr; using namespace SCENE_NS; void PostProcJS::Init(napi_env env, napi_value exports) { using namespace NapiApi; BASE_NS::vector node_props; // clang-format off node_props.push_back(GetSetProperty("bloom")); node_props.emplace_back(GetSetProperty("toneMapping")); node_props.push_back(MakeTROMethod, PostProcJS, &PostProcJS::Dispose>("destroy")); // clang-format on napi_value func; auto status = napi_define_class(env, "PostProcessSettings", NAPI_AUTO_LENGTH, BaseObject::ctor(), nullptr, node_props.size(), node_props.data(), &func); NapiApi::MyInstanceState* mis; napi_get_instance_data(env, (void**)&mis); mis->StoreCtor("PostProcessSettings", func); } napi_value PostProcJS::Dispose(NapiApi::FunctionContext<>& ctx) { LOG_F("PostProcJS::Dispose"); DisposeNative(); return {}; } void PostProcJS::DisposeNative() { if (!disposed_) { disposed_ = true; LOG_F("PostProcJS::DisposeNative"); // make sure we release toneMap settings auto tmjs = toneMap_.GetObject(); if (tmjs) { NapiApi::Function func = tmjs.Get("destroy"); if (func) { func.Invoke(tmjs); } } toneMap_.Reset(); if (auto post = interface_pointer_cast(GetNativeObject())) { // reset the native object refs SetNativeObject(nullptr, false); SetNativeObject(nullptr, true); auto cameraJS = camera_.GetObject(); if (cameraJS) { auto* rootobject = cameraJS.Native(); CameraJS* cam = (CameraJS*)(rootobject); ExecSyncTask([cam, post = BASE_NS::move(post)]() { cam->ReleaseObject(META_NS::interface_pointer_cast(post)); post->Tonemap()->SetValue(nullptr); return META_NS::IAny::Ptr {}; }); } } } } void* PostProcJS::GetInstanceImpl(uint32_t id) { if (id == PostProcJS::ID) { return this; } return nullptr; } void PostProcJS::Finalize(napi_env env) { // need to do something BEFORE the object gets deleted.. DisposeNative(); BaseObject::Finalize(env); } PostProcJS::PostProcJS(napi_env e, napi_callback_info i) : BaseObject(e, i) { LOG_F("PostProcJS ++"); NapiApi::FunctionContext fromJs(e, i); if (!fromJs) { // no arguments. so internal create. // expecting caller to finish return; } // camera that we bind to.. NapiApi::Object cameraJS = fromJs.Arg<0>(); camera_ = { cameraJS }; auto* rootobject = cameraJS.Native(); auto postproc = interface_pointer_cast( ((CameraJS*)(rootobject))->CreateObject(SCENE_NS::ClassId::PostProcess)); // create a postprocess object owned by CameraJS. // process constructor args.. NapiApi::Object meJs(e, fromJs.This()); // weak ref, as we expect to be owned by the camera. SetNativeObject(interface_pointer_cast(postproc), false); StoreJsObj(interface_pointer_cast(postproc), meJs); // now, based on parameters, create correct objects. if (NapiApi::Object args = fromJs.Arg<1>()) { if (auto prm = args.Get("toneMapping")) { // enable tonemap. napi_value args[] = { meJs, // postprocess prm // tonemap settings }; SCENE_NS::ITonemap::Ptr tone; ExecSyncTask([postproc, &tone]() { tone = postproc->Tonemap()->GetValue(); return META_NS::IAny::Ptr {}; }); MakeNativeObjectParam(e, tone, BASE_NS::countof(args), args); NapiApi::Object tonemapJS(GetJSConstructor(e, "ToneMappingSettings"), BASE_NS::countof(args), args); meJs.Set("toneMapping", tonemapJS); } if (auto prm = args.Get("bloom")) { ExecSyncTask([postproc]() -> META_NS::IAny::Ptr { SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue(); bloom->Enabled()->SetValue(true); return {}; }); } } } PostProcJS::~PostProcJS() { LOG_F("PostProcJS --"); DisposeNative(); if (!GetNativeObject()) { return; } } void PostProcJS::SetToneMapping(NapiApi::FunctionContext& ctx) { auto postproc = interface_cast(GetNativeObject()); if (!postproc) { // not possible. return; } NapiApi::Object tonemapJS = ctx.Arg<0>(); if (auto currentlySet = toneMap_.GetObject()) { if ((napi_value)currentlySet == (napi_value)tonemapJS) { // setting the exactly the same tonemap setting. do nothing. return; } // dispose the old bound object.. NapiApi::Function func = currentlySet.Get("destroy"); if (func) { func.Invoke(currentlySet); } toneMap_.Reset(); } TrueRootObject* native { nullptr }; SCENE_NS::ITonemap::Ptr tonemap; // does the input parameter already have a bridge.. native = tonemapJS.Native(); if (!native) { // nope.. so create a new bridge object based on the input. napi_value args[] = { ctx.This(), // postproc.. ctx.Arg<0>() // "javascript object for values" }; NapiApi::Object res(GetJSConstructor(ctx, "ToneMappingSettings"), BASE_NS::countof(args), args); native = res.Native(); tonemapJS = res; } else { tonemap = interface_pointer_cast(native->GetNativeObject()); ExecSyncTask([postproc, tonemap]() { postproc->Tonemap()->SetValue(tonemap); return META_NS::IAny::Ptr {}; }); } toneMap_ = { ctx, tonemapJS }; // take ownership of the object. } napi_value PostProcJS::GetToneMapping(NapiApi::FunctionContext<>& ctx) { if (auto postproc = interface_cast(GetNativeObject())) { SCENE_NS::ITonemap::Ptr tone; ExecSyncTask([postproc, &tone]() { tone = postproc->Tonemap()->GetValue(); return META_NS::IAny::Ptr {}; }); auto obj = interface_pointer_cast(tone); if (auto cached = FetchJsObj(obj)) { // always return the same js object. return cached; } napi_value args[] = { ctx.This() // postproc.. }; MakeNativeObjectParam(ctx, tone, BASE_NS::countof(args), args); napi_value tonemapJS = CreateFromNativeInstance(ctx, obj, false, BASE_NS::countof(args), args); toneMap_ = { ctx, tonemapJS }; // take ownership of the object. return tonemapJS; } toneMap_.Reset(); return ctx.GetUndefined(); } napi_value PostProcJS::GetBloom(NapiApi::FunctionContext<>& ctx) { bool enabled = false; if (auto postproc = interface_pointer_cast(GetNativeObject())) { ExecSyncTask([postproc, &enabled]() { SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue(); enabled = bloom->Enabled()->GetValue(); return META_NS::IAny::Ptr {}; }); } napi_value value; napi_status status = napi_get_boolean(ctx, enabled, &value); return value; } void PostProcJS::SetBloom(NapiApi::FunctionContext& ctx) { bool enable = ctx.Arg<0>(); if (auto postproc = interface_pointer_cast(GetNativeObject())) { ExecSyncTask([postproc, enable]() { SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue(); bloom->Enabled()->SetValue(enable); return META_NS::IAny::Ptr {}; }); } }