/* * 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 "EnvironmentJS.h" #include #include #include #include #include // for the classid.. #include #include #include #include #include #include "SceneJS.h" using namespace SCENE_NS; void EnvironmentJS::Init(napi_env env, napi_value exports) { using namespace NapiApi; BASE_NS::vector node_props; SceneResourceImpl::GetPropertyDescs(node_props); // clang-format off node_props.emplace_back(GetSetProperty("backgroundType")); node_props.emplace_back(GetSetProperty("environmentImage")); node_props.emplace_back(GetSetProperty("radianceImage")); node_props.emplace_back(GetSetProperty("irradianceCoefficients")); node_props.emplace_back(GetSetProperty("indirectDiffuseFactor")); node_props.emplace_back(GetSetProperty("indirectSpecularFactor")); node_props.emplace_back(GetSetProperty("environmentMapFactor")); // clang-format on napi_value func; auto status = napi_define_class(env, "Environment", 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("Environment", func); NapiApi::Object exp(env, exports); napi_value eType; napi_value v; napi_create_object(env, &eType); #define DECL_ENUM(enu, x) \ napi_create_uint32(env, EnvironmentBackgroundType::x, &v); \ napi_set_named_property(env, enu, #x, v) DECL_ENUM(eType, BACKGROUND_NONE); DECL_ENUM(eType, BACKGROUND_IMAGE); DECL_ENUM(eType, BACKGROUND_CUBEMAP); DECL_ENUM(eType, BACKGROUND_EQUIRECTANGULAR); #undef DECL_ENUM exp.Set("EnvironmentBackgroundType", eType); } napi_value EnvironmentJS::Dispose(NapiApi::FunctionContext<>& ctx) { LOG_F("EnvironmentJS::Dispose"); DisposeNative(); return {}; } void EnvironmentJS::DisposeNative() { if (!disposed_) { CORE_LOG_F("EnvironmentJS::DisposeNative"); disposed_ = true; NapiApi::Object obj = scene_.GetObject(); auto* tro = obj.Native(); if (tro) { SceneJS* sceneJS = ((SceneJS*)tro->GetInstanceImpl(SceneJS::ID)); if (sceneJS) { sceneJS->ReleaseStrongDispose((uintptr_t)&scene_); } } diffuseFactor_.reset(); specularFactor_.reset(); environmentFactor_.reset(); if (auto env = interface_pointer_cast(GetNativeObject())) { // reset the native object refs SetNativeObject(nullptr, false); SetNativeObject(nullptr, true); diffuseFactor_.reset(); specularFactor_.reset(); environmentFactor_.reset(); NapiApi::Object sceneJS = scene_.GetObject(); if (sceneJS) { napi_value null; napi_get_null(sceneJS.GetEnv(), &null); sceneJS.Set("environment", null); scene_.Reset(); auto* tro = sceneJS.Native(); IScene::Ptr scene = interface_pointer_cast(tro->GetNativeObject()); ExecSyncTask([s = BASE_NS::move(scene), e = BASE_NS::move(env)]() { auto en = interface_pointer_cast(e); s->ReleaseNode(en); en.reset(); return META_NS::IAny::Ptr {}; }); } } } scene_.Reset(); } void* EnvironmentJS::GetInstanceImpl(uint32_t id) { if (id == EnvironmentJS::ID) { return this; } return SceneResourceImpl::GetInstanceImpl(id); } void EnvironmentJS::Finalize(napi_env env) { // hmm.. do i need to do something BEFORE the object gets deleted.. DisposeNative(); BaseObject::Finalize(env); } EnvironmentJS::EnvironmentJS(napi_env e, napi_callback_info i) : BaseObject(e, i), SceneResourceImpl(SceneResourceImpl::ENVIRONMENT) { LOG_F("EnvironmentJS ++"); NapiApi::FunctionContext fromJs(e, i); if (!fromJs) { // no arguments. so internal create. // expecting caller to finish return; } scene_ = { fromJs, fromJs.Arg<0>() }; if (!GetNativeMeta(scene_.GetObject())) { CORE_LOG_F("INVALID SCENE!"); } NapiApi::Object meJs(e, fromJs.This()); auto* tro = scene_.GetObject().Native(); auto* sceneJS = ((SceneJS*)tro->GetInstanceImpl(SceneJS::ID)); sceneJS->StrongDisposeHook((uintptr_t)&scene_, meJs); IScene::Ptr scene = interface_pointer_cast(tro->GetNativeObject()); NapiApi::Value name; NapiApi::Object args = fromJs.Arg<1>(); if (auto prm = args.Get("name")) { name = NapiApi::Value(e, prm); } BASE_NS::string nameS = name; if (nameS.empty()) { // create "unique" name nameS = BASE_NS::to_string((uint64_t)this); } IEnvironment::Ptr env = GetNativeMeta(meJs); // Construct native object (if needed) if (!env) { ExecSyncTask([&env, scene, nameS]() { BASE_NS::string_view n = nameS; /*nodepath actually*/ env = scene->CreateNode(nameS); return META_NS::IAny::Ptr {}; }); } // process constructor args // weak ref, due to being owned by the scene. SetNativeObject(interface_pointer_cast(env), false); StoreJsObj(interface_pointer_cast(env), meJs); env.reset(); if (name) { // set the name of the object. if we were given one meJs.Set("name", name); } } EnvironmentJS::~EnvironmentJS() { LOG_F("EnvironmentJS --"); DisposeNative(); if (!GetNativeObject()) { return; } } napi_value EnvironmentJS::GetBackgroundType(NapiApi::FunctionContext<>& ctx) { uint32_t typeI = 0; if (auto env = interface_cast(GetNativeObject())) { ExecSyncTask([env, &typeI]() { typeI = env->Background()->GetValue(); return META_NS::IAny::Ptr {}; }); } return NapiApi::Value(ctx, (uint32_t)typeI); } void EnvironmentJS::SetBackgroundType(NapiApi::FunctionContext& ctx) { if (auto env = interface_cast(GetNativeObject())) { uint32_t typeI = ctx.Arg<0>(); auto typeE = static_cast(typeI); IEnvironment::BackgroundType type; switch (typeE) { case EnvironmentBackgroundType::BACKGROUND_NONE: type = IEnvironment::BackgroundType::NONE; break; case EnvironmentBackgroundType::BACKGROUND_IMAGE: type = IEnvironment::BackgroundType::IMAGE; break; case EnvironmentBackgroundType::BACKGROUND_CUBEMAP: type = IEnvironment::BackgroundType::CUBEMAP; break; case EnvironmentBackgroundType::BACKGROUND_EQUIRECTANGULAR: type = IEnvironment::BackgroundType::EQUIRECTANGULAR; break; default: type = IEnvironment::BackgroundType::NONE; break; } ExecSyncTask([env, &type]() { env->Background()->SetValue(type); return META_NS::IAny::Ptr {}; }); } } napi_value EnvironmentJS::GetEnvironmentImage(NapiApi::FunctionContext<>& ctx) { if (auto environment = interface_cast(GetNativeObject())) { SCENE_NS::IBitmap::Ptr image; ExecSyncTask([environment, &image]() { image = environment->EnvironmentImage()->GetValue(); return META_NS::IAny::Ptr {}; }); auto obj = interface_pointer_cast(image); if (auto cached = FetchJsObj(obj)) { return cached; } napi_value args[] = { scene_.GetValue(), NapiApi::Object(ctx) }; return CreateFromNativeInstance(ctx, obj, false, BASE_NS::countof(args), args); } return ctx.GetNull(); } void EnvironmentJS::SetEnvironmentImage(NapiApi::FunctionContext& ctx) { NapiApi::Object imageJS = ctx.Arg<0>(); SCENE_NS::IBitmap::Ptr image; if (auto nat = imageJS.Native()) { image = interface_pointer_cast(nat->GetNativeObject()); } if (auto environment = interface_cast(GetNativeObject())) { ExecSyncTask([environment, image]() { environment->EnvironmentImage()->SetValue(image); return META_NS::IAny::Ptr {}; }); } } napi_value EnvironmentJS::GetRadianceImage(NapiApi::FunctionContext<>& ctx) { if (auto environment = interface_cast(GetNativeObject())) { SCENE_NS::IBitmap::Ptr image; ExecSyncTask([environment, &image]() { image = environment->RadianceImage()->GetValue(); return META_NS::IAny::Ptr {}; }); auto obj = interface_pointer_cast(image); if (auto cached = FetchJsObj(obj)) { return cached; } napi_value args[] = { scene_.GetValue(), NapiApi::Object(ctx) }; return CreateFromNativeInstance(ctx, obj, false, BASE_NS::countof(args), args); } return ctx.GetNull(); } void EnvironmentJS::SetRadianceImage(NapiApi::FunctionContext& ctx) { NapiApi::Object imageJS = ctx.Arg<0>(); SCENE_NS::IBitmap::Ptr image; if (auto nat = imageJS.Native()) { image = interface_pointer_cast(nat->GetNativeObject()); } if (auto environment = interface_cast(GetNativeObject())) { ExecSyncTask([environment, image]() { environment->RadianceImage()->SetValue(image); return META_NS::IAny::Ptr {}; }); } } napi_value EnvironmentJS::GetIrradianceCoefficients(NapiApi::FunctionContext<>& ctx) { BASE_NS::vector coeffs; if (auto environment = interface_cast(GetNativeObject())) { ExecSyncTask([environment, &coeffs]() { coeffs = environment->IrradianceCoefficients()->GetValue(); return META_NS::IAny::Ptr {}; }); } NapiApi::Array res(ctx, 9); // array size 9 size_t index = 0; for (auto& v : coeffs) { NapiApi::Object vec(ctx); vec.Set("x", NapiApi::Value(ctx, v.x)); vec.Set("y", NapiApi::Value(ctx, v.y)); vec.Set("z", NapiApi::Value(ctx, v.z)); res.Set(index++, vec); } return res; } void EnvironmentJS::SetIrradianceCoefficients(NapiApi::FunctionContext& ctx) { NapiApi::Array coeffJS = ctx.Arg<0>(); if (coeffJS.Count() != 9) { // array size 9 // not enough elements in array return; } BASE_NS::vector coeffs; for (auto i = 0; i < coeffJS.Count(); i++) { NapiApi::Object obj = coeffJS.Get(i); if (!obj) { // not an object in array return; } auto x = obj.Get("x"); auto y = obj.Get("y"); auto z = obj.Get("z"); if (!x || !y || !z) { // invalid kind of object. return; } coeffs.emplace_back((float)x, (float)y, (float)z); } if (auto environment = interface_cast(GetNativeObject())) { ExecSyncTask([environment, &coeffs]() { environment->IrradianceCoefficients()->SetValue(coeffs); return META_NS::IAny::Ptr {}; }); } } napi_value EnvironmentJS::GetIndirectDiffuseFactor(NapiApi::FunctionContext<>& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return ctx.GetUndefined(); } if (diffuseFactor_ == nullptr) { diffuseFactor_ = BASE_NS::make_unique(ctx, node->IndirectDiffuseFactor()); } return *diffuseFactor_; } void EnvironmentJS::SetIndirectDiffuseFactor(NapiApi::FunctionContext& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return; } NapiApi::Object obj = ctx.Arg<0>(); if (diffuseFactor_ == nullptr) { diffuseFactor_ = BASE_NS::make_unique(ctx, node->IndirectDiffuseFactor()); } diffuseFactor_->SetValue(obj); } napi_value EnvironmentJS::GetIndirectSpecularFactor(NapiApi::FunctionContext<>& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return ctx.GetUndefined(); } if (specularFactor_ == nullptr) { specularFactor_ = BASE_NS::make_unique(ctx, node->IndirectSpecularFactor()); } return *specularFactor_; } void EnvironmentJS::SetIndirectSpecularFactor(NapiApi::FunctionContext& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return; } NapiApi::Object obj = ctx.Arg<0>(); if (specularFactor_ == nullptr) { specularFactor_ = BASE_NS::make_unique(ctx, node->IndirectSpecularFactor()); } specularFactor_->SetValue(obj); } napi_value EnvironmentJS::GetEnvironmentMapFactor(NapiApi::FunctionContext<>& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return ctx.GetUndefined(); } if (environmentFactor_ == nullptr) { environmentFactor_ = BASE_NS::make_unique(ctx, node->EnvMapFactor()); } return *environmentFactor_; } void EnvironmentJS::SetEnvironmentMapFactor(NapiApi::FunctionContext& ctx) { auto node = interface_pointer_cast(GetThisNativeObject(ctx)); if (!node) { return; } NapiApi::Object obj = ctx.Arg<0>(); if (environmentFactor_ == nullptr) { environmentFactor_ = BASE_NS::make_unique(ctx, node->EnvMapFactor()); } environmentFactor_->SetValue(obj); }