* Copyright (C) 2025 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 <algorithm>
#include <base/math/vector.h>
#include <base/util/color.h>
#include "SceneResourceFactoryImpl.h"
#include "EffectImpl.h"
#include "OcclusionMaterialImpl.h"
#include "PBRMaterialImpl.h"
#include "ParamUtils.h"
#include "interop_js/arkts_interop_js_api.h"
#include "interop_js/arkts_esvalue.h"
#include "BaseObjectJS.h"
#include "nodejstaskqueue.h"
#include "SceneJS.h"
namespace OHOS::Render3D::KITETS {
::SceneNodes::Camera SceneResourceFactoryImpl::createCameraSync(::SceneTH::SceneNodeParameters const& params)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return SceneNodes::Camera({nullptr, nullptr});
}
std::string nodePath = ExtractNodePath(params);
InvokeReturn<std::shared_ptr<CameraETS>> camera = sceneETS_->CreateCamera(nodePath);
if (camera.error.empty()) {
return taihe::make_holder<CameraImpl, ::SceneNodes::Camera>(camera.value);
} else {
taihe::set_error(camera.error);
return SceneNodes::Camera({nullptr, nullptr});
}
}
::SceneNodes::Camera SceneResourceFactoryImpl::createCameraSyncWithCameraParams(
::SceneTH::SceneNodeParameters const& params, ::SceneTH::CameraParameters const& cameraParams)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return SceneNodes::Camera({nullptr, nullptr});
}
bool msaa = false;
if (cameraParams.msaa) {
msaa = cameraParams.msaa.value();
}
uint32_t pipeline = uint32_t(SCENE_NS::CameraPipeline::LIGHT_FORWARD);
if (cameraParams.renderingPipeline) {
pipeline = cameraParams.renderingPipeline.value();
}
std::string nodePath = ExtractNodePath(params);
InvokeReturn<std::shared_ptr<CameraETS>> camera = sceneETS_->CreateCamera(nodePath, pipeline, msaa);
if (camera.error.empty()) {
return taihe::make_holder<CameraImpl, ::SceneNodes::Camera>(camera.value);
} else {
taihe::set_error(camera.error);
return SceneNodes::Camera({nullptr, nullptr});
}
}
::SceneNodes::LightTypeUnion SceneResourceFactoryImpl::createLightSync(
::SceneTH::SceneNodeParameters const& params, ::SceneNodes::LightType lightType)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return SceneNodes::LightTypeUnion::make_base(SceneNodes::Light({nullptr, nullptr}));
}
std::string nodeName = ExtractNodeName(params);
std::string nodePath = ExtractNodePath(params);
LightETS::LightType type = LightETS::LightType(lightType.get_value());
InvokeReturn<std::shared_ptr<LightETS>> light = sceneETS_->CreateLight(nodeName, nodePath, type);
if (!light) {
taihe::set_error(light.error);
return SceneNodes::LightTypeUnion::make_base(SceneNodes::Light({nullptr, nullptr}));
}
switch (type) {
case LightETS::LightType::DIRECTIONAL:
return ::SceneNodes::LightTypeUnion::make_directional(
taihe::make_holder<DirectionalLightImpl, ::SceneNodes::DirectionalLight>(light.value));
case LightETS::LightType::SPOT:
return ::SceneNodes::LightTypeUnion::make_spot(
taihe::make_holder<SpotLightImpl, ::SceneNodes::SpotLight>(light.value));
case LightETS::LightType::POINT:
return ::SceneNodes::LightTypeUnion::make_base(
taihe::make_holder<LightImpl, ::SceneNodes::Light>(light.value));
default:
return ::SceneNodes::LightTypeUnion::make_base(
taihe::make_holder<LightImpl, ::SceneNodes::Light>(light.value));
}
}
::SceneNodes::Node SceneResourceFactoryImpl::createNodeSync(::SceneTH::SceneNodeParameters const& params)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return SceneNodes::Node({nullptr, nullptr});
}
std::string nodePath = ExtractNodePath(params);
WIDGET_LOGE("SceneResourceFactoryImpl::createNodeSync, nodePath: %{public}s", nodePath.c_str());
InvokeReturn<std::shared_ptr<NodeETS>> node = sceneETS_->CreateNode(nodePath);
if (node.error.empty()) {
return taihe::make_holder<NodeImpl, ::SceneNodes::Node>(node.value);
} else {
taihe::set_error(node.error);
return SceneNodes::Node({nullptr, nullptr});
}
}
::SceneResources::VariousMaterial SceneResourceFactoryImpl::createMaterialSync(
::SceneTH::SceneResourceParameters const& params, ::SceneResources::MaterialType materialType)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene ets");
auto mat = ::SceneResources::MetallicRoughnessMaterial({nullptr, nullptr});
return ::SceneResources::VariousMaterial::make_metaRough(mat);
}
std::string name = std::string(params.name);
std::string uri = ExtractUri(params.uri);
MaterialETS::MaterialType type;
if (materialType == ::SceneResources::MaterialType::key_t::SHADER) {
type = MaterialETS::MaterialType::SHADER;
} else if (materialType == ::SceneResources::MaterialType::key_t::UNLIT) {
type = MaterialETS::MaterialType::UNLIT;
} else if (materialType == ::SceneResources::MaterialType::key_t::UNLIT_SHADOW_ALPHA) {
type = MaterialETS::MaterialType::UNLIT_SHADOW_ALPHA;
} else if (materialType == ::SceneResources::MaterialType::key_t::OCCLUSION) {
type = MaterialETS::MaterialType::OCCLUSION;
} else {
type = MaterialETS::MaterialType::METALLIC_ROUGHNESS;
}
InvokeReturn<std::shared_ptr<MaterialETS>> material = sceneETS_->CreateMaterial(name, uri, type);
if (!material) {
taihe::set_error(material.error);
auto mat = ::SceneResources::PBRMaterial({nullptr, nullptr});
return ::SceneResources::VariousMaterial::make_pbr(mat);
}
if (type == MaterialETS::MaterialType::OCCLUSION) {
auto mat = ::taihe::make_holder<OcclusionMaterialImpl, ::SceneResources::OcclusionMaterial>(material.value);
return ::SceneResources::VariousMaterial::make_occlusion(mat);
} else {
auto mat = ::taihe::make_holder<PBRMaterialImpl, ::SceneResources::PBRMaterial>(material.value);
return ::SceneResources::VariousMaterial::make_pbr(mat);
}
}
::SceneResources::Environment SceneResourceFactoryImpl::createEnvironmentSync(
::SceneTH::SceneResourceParameters const& params)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return ::SceneResources::Environment({nullptr, nullptr});
}
std::string name = ExtractResourceName(params);
std::string uri = ExtractUri(params.uri);
WIDGET_LOGI("createEnvironmentSync, SceneResource name: %{public}s uri: %{public}s", name.c_str(), uri.c_str());
InvokeReturn<std::shared_ptr<EnvironmentETS>> environment = sceneETS_->CreateEnvironment(name, uri);
if (environment.error.empty()) {
return taihe::make_holder<EnvironmentImpl, ::SceneResources::Environment>(environment.value);
} else {
taihe::set_error(environment.error);
return ::SceneResources::Environment({nullptr, nullptr});
}
}
::SceneNodes::Geometry SceneResourceFactoryImpl::createGeometrySync(
::SceneTH::SceneNodeParameters const& params, ::SceneResources::weak::MeshResource mesh)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return SceneNodes::Geometry({nullptr, nullptr});
}
if (mesh.is_error()) {
taihe::set_error("Invalid mesh resource given");
return SceneNodes::Geometry({nullptr, nullptr});
}
auto meshOptional = static_cast<::SceneResources::weak::SceneResource>(mesh)->getImpl();
if (!meshOptional.has_value()) {
taihe::set_error("invalid mesh in taihe object");
return SceneNodes::Geometry({nullptr, nullptr});
}
auto mri = reinterpret_cast<MeshResourceImpl*>(meshOptional.value());
if (mri == nullptr || !(mri->mrETS_)) {
taihe::set_error("Invalid MeshResource");
return SceneNodes::Geometry({nullptr, nullptr});
}
std::string nodePath = ExtractNodePath(params);
InvokeReturn<std::shared_ptr<GeometryETS>> geom = sceneETS_->CreateGeometry(nodePath, mri->mrETS_);
if (geom.error.empty()) {
return taihe::make_holder<GeometryImpl, ::SceneNodes::Geometry>(geom.value);
} else {
taihe::set_error(geom.error);
return SceneNodes::Geometry({nullptr, nullptr});
}
}
::SceneResources::Effect SceneResourceFactoryImpl::createEffectSync(::SceneTH::EffectParameters const& params)
{
if (!sceneETS_) {
taihe::set_error("Invalid scene");
return ::SceneResources::Effect({nullptr, nullptr});
}
std::string effectId = std::string(params.effectId);
InvokeReturn<std::shared_ptr<EffectETS>> effect = sceneETS_->CreateEffect(effectId.c_str());
if (effect.error.empty()) {
return taihe::make_holder<EffectImpl, ::SceneResources::Effect>(effect.value);
} else {
taihe::set_error(effect.error);
return ::SceneResources::Effect({nullptr, nullptr});
}
}
::SceneTH::SceneResourceFactory sceneResourceFactoryTransferStaticImpl(uintptr_t input)
{
ani_object esValue = reinterpret_cast<ani_object>(input);
void* nativePtr = nullptr;
if (!arkts_esvalue_unwrap(taihe::get_env(), esValue, &nativePtr) || nativePtr == nullptr) {
WIDGET_LOGE("unwrap esvalue failed");
return SceneTH::SceneResourceFactory({nullptr, nullptr});
}
auto sceneJS = reinterpret_cast<SceneJS*>(nativePtr);
if (!sceneJS) {
WIDGET_LOGE("transfer SceneResourceFactory failed");
return SceneTH::SceneResourceFactory({nullptr, nullptr});
}
SCENE_NS::IScene::Ptr scene = sceneJS->GetNativeObject<SCENE_NS::IScene>();
std::shared_ptr<OHOS::Render3D::ISceneAdapter> sceneAdapter = sceneJS->scene_;
auto sceneETS = std::make_shared<SceneETS>(scene, sceneAdapter);
return taihe::make_holder<SceneResourceFactoryImpl, SceneTH::SceneResourceFactory>(sceneETS);
}
uintptr_t sceneResourceFactoryTransferDynamicImpl(::SceneTH::weak::SceneResourceFactory input)
{
taihe::optional<int64_t> implOp = input->getImpl();
if (!implOp.has_value()) {
WIDGET_LOGE("get SceneResourceFactoryImpl failed");
return 0;
}
SceneResourceFactoryImpl* srfi = reinterpret_cast<SceneResourceFactoryImpl*>(implOp.value());
if (srfi == nullptr) {
WIDGET_LOGE("can't cast to SceneResourceFactoryImpl");
return 0;
}
std::shared_ptr<SceneETS> internalScene = srfi->getInternalScene();
if (!internalScene) {
WIDGET_LOGE("get SceneETS failed");
return 0;
}
SCENE_NS::IScene::Ptr nativeObj = internalScene->GetNativeScene();
if (!nativeObj) {
WIDGET_LOGE("get IScene failed");
return 0;
}
napi_env jsenv;
if (!arkts_napi_scope_open(taihe::get_env(), &jsenv)) {
WIDGET_LOGE("arkts_napi_scope_open failed");
return 0;
}
if (!CheckNapiEnv(jsenv)) {
WIDGET_LOGE("CheckNapiEnv failed");
arkts_napi_scope_close_n(jsenv, 0, nullptr, nullptr);
return 0;
}
auto sceneJs = CreateFromNativeInstance(jsenv, nativeObj, PtrType::STRONG, {});
if (!sceneJs) {
WIDGET_LOGE("create SceneJS failed");
arkts_napi_scope_close_n(jsenv, 0, nullptr, nullptr);
return 0;
}
napi_value sceneValue = sceneJs.ToNapiValue();
ani_ref resAny;
if (!arkts_napi_scope_close_n(jsenv, 1, &sceneValue, &resAny)) {
WIDGET_LOGE("arkts_napi_scope_close_n failed");
return 0;
}
return reinterpret_cast<uintptr_t>(resAny);
}
}
using namespace OHOS::Render3D::KITETS;
TH_EXPORT_CPP_API_sceneResourceFactoryTransferStaticImpl(sceneResourceFactoryTransferStaticImpl);
TH_EXPORT_CPP_API_sceneResourceFactoryTransferDynamicImpl(sceneResourceFactoryTransferDynamicImpl);