18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "PostProcJS.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
198bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue.h>
208bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h>
218bf80f4bSopenharmony_ci#include <meta/interface/property/property_events.h>
228bf80f4bSopenharmony_ci#include <scene_plugin/api/camera.h> //for the classid...
238bf80f4bSopenharmony_ci#include <scene_plugin/api/node_uid.h>
248bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_ecs_scene.h>
258bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_node.h>
268bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_scene.h>
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ci#include <render/intf_render_context.h>
298bf80f4bSopenharmony_ci
308bf80f4bSopenharmony_ci#include "CameraJS.h"
318bf80f4bSopenharmony_ciusing IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
328bf80f4bSopenharmony_ciusing IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
338bf80f4bSopenharmony_ciusing namespace SCENE_NS;
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_civoid PostProcJS::Init(napi_env env, napi_value exports)
368bf80f4bSopenharmony_ci{
378bf80f4bSopenharmony_ci    using namespace NapiApi;
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ci    BASE_NS::vector<napi_property_descriptor> node_props;
408bf80f4bSopenharmony_ci    // clang-format off
418bf80f4bSopenharmony_ci
428bf80f4bSopenharmony_ci    node_props.push_back(GetSetProperty<bool, PostProcJS, &PostProcJS::GetBloom, &PostProcJS::SetBloom>("bloom"));
438bf80f4bSopenharmony_ci    node_props.emplace_back(GetSetProperty<Object, PostProcJS, &PostProcJS::GetToneMapping,
448bf80f4bSopenharmony_ci        &PostProcJS::SetToneMapping>("toneMapping"));
458bf80f4bSopenharmony_ci    node_props.push_back(MakeTROMethod<NapiApi::FunctionContext<>, PostProcJS, &PostProcJS::Dispose>("destroy"));
468bf80f4bSopenharmony_ci
478bf80f4bSopenharmony_ci    // clang-format on
488bf80f4bSopenharmony_ci
498bf80f4bSopenharmony_ci    napi_value func;
508bf80f4bSopenharmony_ci    auto status = napi_define_class(env, "PostProcessSettings", NAPI_AUTO_LENGTH, BaseObject::ctor<PostProcJS>(),
518bf80f4bSopenharmony_ci        nullptr, node_props.size(), node_props.data(), &func);
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_ci    NapiApi::MyInstanceState* mis;
548bf80f4bSopenharmony_ci    napi_get_instance_data(env, (void**)&mis);
558bf80f4bSopenharmony_ci    mis->StoreCtor("PostProcessSettings", func);
568bf80f4bSopenharmony_ci}
578bf80f4bSopenharmony_ci
588bf80f4bSopenharmony_cinapi_value PostProcJS::Dispose(NapiApi::FunctionContext<>& ctx)
598bf80f4bSopenharmony_ci{
608bf80f4bSopenharmony_ci    LOG_F("PostProcJS::Dispose");
618bf80f4bSopenharmony_ci    DisposeNative();
628bf80f4bSopenharmony_ci    return {};
638bf80f4bSopenharmony_ci}
648bf80f4bSopenharmony_civoid PostProcJS::DisposeNative()
658bf80f4bSopenharmony_ci{
668bf80f4bSopenharmony_ci    if (!disposed_) {
678bf80f4bSopenharmony_ci        disposed_ = true;
688bf80f4bSopenharmony_ci        LOG_F("PostProcJS::DisposeNative");
698bf80f4bSopenharmony_ci        // make sure we release toneMap settings
708bf80f4bSopenharmony_ci
718bf80f4bSopenharmony_ci        auto tmjs = toneMap_.GetObject();
728bf80f4bSopenharmony_ci        if (tmjs) {
738bf80f4bSopenharmony_ci            NapiApi::Function func = tmjs.Get<NapiApi::Function>("destroy");
748bf80f4bSopenharmony_ci            if (func) {
758bf80f4bSopenharmony_ci                func.Invoke(tmjs);
768bf80f4bSopenharmony_ci            }
778bf80f4bSopenharmony_ci        }
788bf80f4bSopenharmony_ci        toneMap_.Reset();
798bf80f4bSopenharmony_ci
808bf80f4bSopenharmony_ci        if (auto post = interface_pointer_cast<IPostProcess>(GetNativeObject())) {
818bf80f4bSopenharmony_ci            // reset the native object refs
828bf80f4bSopenharmony_ci            SetNativeObject(nullptr, false);
838bf80f4bSopenharmony_ci            SetNativeObject(nullptr, true);
848bf80f4bSopenharmony_ci
858bf80f4bSopenharmony_ci            auto cameraJS = camera_.GetObject();
868bf80f4bSopenharmony_ci            if (cameraJS) {
878bf80f4bSopenharmony_ci                auto* rootobject = cameraJS.Native<TrueRootObject>();
888bf80f4bSopenharmony_ci                CameraJS* cam = (CameraJS*)(rootobject);
898bf80f4bSopenharmony_ci
908bf80f4bSopenharmony_ci                ExecSyncTask([cam, post = BASE_NS::move(post)]() {
918bf80f4bSopenharmony_ci                    cam->ReleaseObject(META_NS::interface_pointer_cast<META_NS::IObject>(post));
928bf80f4bSopenharmony_ci                    post->Tonemap()->SetValue(nullptr);
938bf80f4bSopenharmony_ci                    return META_NS::IAny::Ptr {};
948bf80f4bSopenharmony_ci                });
958bf80f4bSopenharmony_ci            }
968bf80f4bSopenharmony_ci        }
978bf80f4bSopenharmony_ci    }
988bf80f4bSopenharmony_ci}
998bf80f4bSopenharmony_civoid* PostProcJS::GetInstanceImpl(uint32_t id)
1008bf80f4bSopenharmony_ci{
1018bf80f4bSopenharmony_ci    if (id == PostProcJS::ID) {
1028bf80f4bSopenharmony_ci        return this;
1038bf80f4bSopenharmony_ci    }
1048bf80f4bSopenharmony_ci    return nullptr;
1058bf80f4bSopenharmony_ci}
1068bf80f4bSopenharmony_civoid PostProcJS::Finalize(napi_env env)
1078bf80f4bSopenharmony_ci{
1088bf80f4bSopenharmony_ci    // need to do something BEFORE the object gets deleted..
1098bf80f4bSopenharmony_ci    DisposeNative();
1108bf80f4bSopenharmony_ci    BaseObject<PostProcJS>::Finalize(env);
1118bf80f4bSopenharmony_ci}
1128bf80f4bSopenharmony_ci
1138bf80f4bSopenharmony_ciPostProcJS::PostProcJS(napi_env e, napi_callback_info i) : BaseObject<PostProcJS>(e, i)
1148bf80f4bSopenharmony_ci{
1158bf80f4bSopenharmony_ci    LOG_F("PostProcJS ++");
1168bf80f4bSopenharmony_ci    NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
1178bf80f4bSopenharmony_ci    if (!fromJs) {
1188bf80f4bSopenharmony_ci        // no arguments. so internal create.
1198bf80f4bSopenharmony_ci        // expecting caller to finish
1208bf80f4bSopenharmony_ci        return;
1218bf80f4bSopenharmony_ci    }
1228bf80f4bSopenharmony_ci
1238bf80f4bSopenharmony_ci    // camera that we bind to..
1248bf80f4bSopenharmony_ci    NapiApi::Object cameraJS = fromJs.Arg<0>();
1258bf80f4bSopenharmony_ci    camera_ = { cameraJS };
1268bf80f4bSopenharmony_ci    auto* rootobject = cameraJS.Native<TrueRootObject>();
1278bf80f4bSopenharmony_ci    auto postproc = interface_pointer_cast<SCENE_NS::IPostProcess>(
1288bf80f4bSopenharmony_ci        ((CameraJS*)(rootobject))->CreateObject(SCENE_NS::ClassId::PostProcess));
1298bf80f4bSopenharmony_ci
1308bf80f4bSopenharmony_ci    // create a postprocess object owned by CameraJS.
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_ci    // process constructor args..
1338bf80f4bSopenharmony_ci    NapiApi::Object meJs(e, fromJs.This());
1348bf80f4bSopenharmony_ci    // weak ref, as we expect to be owned by the camera.
1358bf80f4bSopenharmony_ci    SetNativeObject(interface_pointer_cast<META_NS::IObject>(postproc), false);
1368bf80f4bSopenharmony_ci    StoreJsObj(interface_pointer_cast<META_NS::IObject>(postproc), meJs);
1378bf80f4bSopenharmony_ci    // now, based on parameters, create correct objects.
1388bf80f4bSopenharmony_ci    if (NapiApi::Object args = fromJs.Arg<1>()) {
1398bf80f4bSopenharmony_ci        if (auto prm = args.Get("toneMapping")) {
1408bf80f4bSopenharmony_ci            // enable tonemap.
1418bf80f4bSopenharmony_ci            napi_value args[] = {
1428bf80f4bSopenharmony_ci                meJs, // postprocess
1438bf80f4bSopenharmony_ci                prm   // tonemap settings
1448bf80f4bSopenharmony_ci            };
1458bf80f4bSopenharmony_ci            SCENE_NS::ITonemap::Ptr tone;
1468bf80f4bSopenharmony_ci            ExecSyncTask([postproc, &tone]() {
1478bf80f4bSopenharmony_ci                tone = postproc->Tonemap()->GetValue();
1488bf80f4bSopenharmony_ci                return META_NS::IAny::Ptr {};
1498bf80f4bSopenharmony_ci            });
1508bf80f4bSopenharmony_ci            MakeNativeObjectParam(e, tone, BASE_NS::countof(args), args);
1518bf80f4bSopenharmony_ci            NapiApi::Object tonemapJS(GetJSConstructor(e, "ToneMappingSettings"), BASE_NS::countof(args), args);
1528bf80f4bSopenharmony_ci            meJs.Set("toneMapping", tonemapJS);
1538bf80f4bSopenharmony_ci        }
1548bf80f4bSopenharmony_ci        if (auto prm = args.Get("bloom")) {
1558bf80f4bSopenharmony_ci            ExecSyncTask([postproc]() -> META_NS::IAny::Ptr {
1568bf80f4bSopenharmony_ci                SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue();
1578bf80f4bSopenharmony_ci                bloom->Enabled()->SetValue(true);
1588bf80f4bSopenharmony_ci                return {};
1598bf80f4bSopenharmony_ci            });
1608bf80f4bSopenharmony_ci        }
1618bf80f4bSopenharmony_ci    }
1628bf80f4bSopenharmony_ci}
1638bf80f4bSopenharmony_ci
1648bf80f4bSopenharmony_ciPostProcJS::~PostProcJS()
1658bf80f4bSopenharmony_ci{
1668bf80f4bSopenharmony_ci    LOG_F("PostProcJS --");
1678bf80f4bSopenharmony_ci    DisposeNative();
1688bf80f4bSopenharmony_ci    if (!GetNativeObject()) {
1698bf80f4bSopenharmony_ci        return;
1708bf80f4bSopenharmony_ci    }
1718bf80f4bSopenharmony_ci}
1728bf80f4bSopenharmony_ci
1738bf80f4bSopenharmony_civoid PostProcJS::SetToneMapping(NapiApi::FunctionContext<NapiApi::Object>& ctx)
1748bf80f4bSopenharmony_ci{
1758bf80f4bSopenharmony_ci    auto postproc = interface_cast<SCENE_NS::IPostProcess>(GetNativeObject());
1768bf80f4bSopenharmony_ci    if (!postproc) {
1778bf80f4bSopenharmony_ci        // not possible.
1788bf80f4bSopenharmony_ci        return;
1798bf80f4bSopenharmony_ci    }
1808bf80f4bSopenharmony_ci    NapiApi::Object tonemapJS = ctx.Arg<0>();
1818bf80f4bSopenharmony_ci
1828bf80f4bSopenharmony_ci    if (auto currentlySet = toneMap_.GetObject()) {
1838bf80f4bSopenharmony_ci        if ((napi_value)currentlySet == (napi_value)tonemapJS) {
1848bf80f4bSopenharmony_ci            // setting the exactly the same tonemap setting. do nothing.
1858bf80f4bSopenharmony_ci            return;
1868bf80f4bSopenharmony_ci        }
1878bf80f4bSopenharmony_ci        // dispose the old bound object..
1888bf80f4bSopenharmony_ci        NapiApi::Function func = currentlySet.Get<NapiApi::Function>("destroy");
1898bf80f4bSopenharmony_ci        if (func) {
1908bf80f4bSopenharmony_ci            func.Invoke(currentlySet);
1918bf80f4bSopenharmony_ci        }
1928bf80f4bSopenharmony_ci        toneMap_.Reset();
1938bf80f4bSopenharmony_ci    }
1948bf80f4bSopenharmony_ci
1958bf80f4bSopenharmony_ci    TrueRootObject* native { nullptr };
1968bf80f4bSopenharmony_ci    SCENE_NS::ITonemap::Ptr tonemap;
1978bf80f4bSopenharmony_ci    // does the input parameter already have a bridge..
1988bf80f4bSopenharmony_ci    native = tonemapJS.Native<TrueRootObject>();
1998bf80f4bSopenharmony_ci    if (!native) {
2008bf80f4bSopenharmony_ci        // nope.. so create a new bridge object based on the input.
2018bf80f4bSopenharmony_ci        napi_value args[] = {
2028bf80f4bSopenharmony_ci            ctx.This(), // postproc..
2038bf80f4bSopenharmony_ci            ctx.Arg<0>() // "javascript object for values"
2048bf80f4bSopenharmony_ci        };
2058bf80f4bSopenharmony_ci        NapiApi::Object res(GetJSConstructor(ctx, "ToneMappingSettings"), BASE_NS::countof(args), args);
2068bf80f4bSopenharmony_ci        native = res.Native<TrueRootObject>();
2078bf80f4bSopenharmony_ci        tonemapJS = res;
2088bf80f4bSopenharmony_ci    } else {
2098bf80f4bSopenharmony_ci        tonemap = interface_pointer_cast<SCENE_NS::ITonemap>(native->GetNativeObject());
2108bf80f4bSopenharmony_ci        ExecSyncTask([postproc, tonemap]() {
2118bf80f4bSopenharmony_ci            postproc->Tonemap()->SetValue(tonemap);
2128bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2138bf80f4bSopenharmony_ci        });
2148bf80f4bSopenharmony_ci    }
2158bf80f4bSopenharmony_ci    toneMap_ = { ctx, tonemapJS }; // take ownership of the object.
2168bf80f4bSopenharmony_ci}
2178bf80f4bSopenharmony_ci
2188bf80f4bSopenharmony_cinapi_value PostProcJS::GetToneMapping(NapiApi::FunctionContext<>& ctx)
2198bf80f4bSopenharmony_ci{
2208bf80f4bSopenharmony_ci    if (auto postproc = interface_cast<SCENE_NS::IPostProcess>(GetNativeObject())) {
2218bf80f4bSopenharmony_ci        SCENE_NS::ITonemap::Ptr tone;
2228bf80f4bSopenharmony_ci        ExecSyncTask([postproc, &tone]() {
2238bf80f4bSopenharmony_ci            tone = postproc->Tonemap()->GetValue();
2248bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2258bf80f4bSopenharmony_ci        });
2268bf80f4bSopenharmony_ci        auto obj = interface_pointer_cast<META_NS::IObject>(tone);
2278bf80f4bSopenharmony_ci
2288bf80f4bSopenharmony_ci        if (auto cached = FetchJsObj(obj)) {
2298bf80f4bSopenharmony_ci            // always return the same js object.
2308bf80f4bSopenharmony_ci            return cached;
2318bf80f4bSopenharmony_ci        }
2328bf80f4bSopenharmony_ci
2338bf80f4bSopenharmony_ci        napi_value args[] = {
2348bf80f4bSopenharmony_ci            ctx.This() // postproc..
2358bf80f4bSopenharmony_ci        };
2368bf80f4bSopenharmony_ci        MakeNativeObjectParam(ctx, tone, BASE_NS::countof(args), args);
2378bf80f4bSopenharmony_ci        napi_value tonemapJS = CreateFromNativeInstance(ctx, obj, false, BASE_NS::countof(args), args);
2388bf80f4bSopenharmony_ci        toneMap_ = { ctx, tonemapJS }; // take ownership of the object.
2398bf80f4bSopenharmony_ci        return tonemapJS;
2408bf80f4bSopenharmony_ci    }
2418bf80f4bSopenharmony_ci    toneMap_.Reset();
2428bf80f4bSopenharmony_ci    return ctx.GetUndefined();
2438bf80f4bSopenharmony_ci}
2448bf80f4bSopenharmony_ci
2458bf80f4bSopenharmony_cinapi_value PostProcJS::GetBloom(NapiApi::FunctionContext<>& ctx)
2468bf80f4bSopenharmony_ci{
2478bf80f4bSopenharmony_ci    bool enabled = false;
2488bf80f4bSopenharmony_ci    if (auto postproc = interface_pointer_cast<SCENE_NS::IPostProcess>(GetNativeObject())) {
2498bf80f4bSopenharmony_ci        ExecSyncTask([postproc, &enabled]() {
2508bf80f4bSopenharmony_ci            SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue();
2518bf80f4bSopenharmony_ci            enabled = bloom->Enabled()->GetValue();
2528bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2538bf80f4bSopenharmony_ci        });
2548bf80f4bSopenharmony_ci    }
2558bf80f4bSopenharmony_ci
2568bf80f4bSopenharmony_ci    napi_value value;
2578bf80f4bSopenharmony_ci    napi_status status = napi_get_boolean(ctx, enabled, &value);
2588bf80f4bSopenharmony_ci    return value;
2598bf80f4bSopenharmony_ci}
2608bf80f4bSopenharmony_ci
2618bf80f4bSopenharmony_civoid PostProcJS::SetBloom(NapiApi::FunctionContext<bool>& ctx)
2628bf80f4bSopenharmony_ci{
2638bf80f4bSopenharmony_ci    bool enable = ctx.Arg<0>();
2648bf80f4bSopenharmony_ci    if (auto postproc = interface_pointer_cast<SCENE_NS::IPostProcess>(GetNativeObject())) {
2658bf80f4bSopenharmony_ci        ExecSyncTask([postproc, enable]() {
2668bf80f4bSopenharmony_ci            SCENE_NS::IBloom::Ptr bloom = postproc->Bloom()->GetValue();
2678bf80f4bSopenharmony_ci            bloom->Enabled()->SetValue(enable);
2688bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2698bf80f4bSopenharmony_ci        });
2708bf80f4bSopenharmony_ci    }
2718bf80f4bSopenharmony_ci}
272