* 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 "ANIUtils.h"
#include "MeshResourceImpl.h"
#include "TaiheErrorUtil.h"
#include "geometry_definition/GeometryDefinition.h"
#ifdef __SCENE_ADAPTER__
#include "3d_widget_adapter_log.h"
#endif
namespace OHOS::Render3D::KITETS {
static constexpr int CYLINDER_MIN_SEGMENTS = 3;
BASE_NS::unique_ptr<Geometry::CustomETS> MeshResourceImpl::MakeCustomETS(
const SceneTypes::CustomGeometry &customGeometry)
{
const taihe::optional<SceneTypes::PrimitiveTopology> topologyOP = customGeometry->getTopology();
Geometry::CustomETS::PrimitiveTopology topology;
if (topologyOP.has_value()) {
topology = static_cast<Geometry::CustomETS::PrimitiveTopology>(topologyOP.value().get_value());
} else {
topology = Geometry::CustomETS::PrimitiveTopology::TRIANGLE_LIST;
}
auto vertices = ArrayToVector<SceneTypes::Vec3, BASE_NS::Math::Vec3>(customGeometry->getVertices(),
[](const SceneTypes::Vec3 &a) { return BASE_NS::Math::Vec3(a->getX(), a->getY(), a->getZ()); });
const auto vertexCount = static_cast<uint32_t>(vertices.size());
const auto indicesOpt = customGeometry->getIndices();
BASE_NS::vector<uint32_t> indices;
if (indicesOpt.has_value()) {
const auto &indicesArray = indicesOpt.value();
indices.resize(indicesArray.size());
for (size_t i = 0; i < indicesArray.size(); ++i) {
const uint32_t idx = static_cast<uint32_t>(indicesArray[i]);
if (idx >= vertexCount) {
SetBusinessError(ErrorCode::INVALID_ARGUMENTS,
"Invalid index in CustomGeometry: index %d out of range [0, %u)",
static_cast<int32_t>(idx), vertexCount);
return nullptr;
}
indices[i] = idx;
}
}
auto normals = ArrayToVector<SceneTypes::Vec3, BASE_NS::Math::Vec3>(customGeometry->getNormals(),
[](const SceneTypes::Vec3 &a) { return BASE_NS::Math::Vec3(a->getX(), a->getY(), a->getZ()); });
auto uvs = ArrayToVector<SceneTypes::Vec2, BASE_NS::Math::Vec2>(
customGeometry->getUvs(), [](const SceneTypes::Vec2 &a) { return BASE_NS::Math::Vec2(a->getX(), a->getY()); });
auto colors = ArrayToVector<SceneTypes::Color, BASE_NS::Color>(customGeometry->getColors(),
[](const SceneTypes::Color &a) { return BASE_NS::Color(a->getR(), a->getG(), a->getB(), a->getA()); });
return BASE_NS::make_unique<Geometry::CustomETS>(topology, vertices, indices, normals, uvs, colors);
}
SceneResources::MeshResource MeshResourceImpl::Create(
SceneTH::SceneResourceParameters const ¶ms, ::SceneTypes::GeometryDefinitionType const &geometry)
{
BASE_NS::unique_ptr<Geometry::GeometryDefinition> gd{nullptr};
if (geometry.holds_custom()) {
const SceneTypes::CustomGeometry &customGeometry = geometry.get_custom_ref();
gd = MakeCustomETS(customGeometry);
if (!gd) {
return ::taihe::make_holder<MeshResourceImpl, SceneResources::MeshResource>(nullptr);
}
} else if (geometry.holds_cube()) {
const SceneTypes::CubeGeometry &cubeGeometry = geometry.get_cube_ref();
SceneTypes::Vec3 size = cubeGeometry->getSize();
gd = BASE_NS::make_unique<Geometry::CubeETS>(
BASE_NS::Math::Vec3(size->getX(), size->getY(), size->getZ()));
} else if (geometry.holds_plane()) {
const SceneTypes::PlaneGeometry &planeGeometry = geometry.get_plane_ref();
SceneTypes::Vec2 size = planeGeometry->getSize();
gd = BASE_NS::make_unique<Geometry::PlaneETS>(BASE_NS::Math::Vec2(size->getX(), size->getY()));
} else if (geometry.holds_sphere()) {
const SceneTypes::SphereGeometry &sphereGeometry = geometry.get_sphere_ref();
float radius = sphereGeometry->getRadius();
int segmentCount = sphereGeometry->getSegmentCount();
gd = BASE_NS::make_unique<Geometry::SphereETS>(radius, segmentCount);
} else if (geometry.holds_cylinder()) {
const SceneTypes::CylinderGeometry &cylinderGeometry = geometry.get_cylinder_ref();
float radius = cylinderGeometry->getRadius();
float height = cylinderGeometry->getHeight();
int segmentCount = cylinderGeometry->getSegmentCount();
if (radius > 0 && height > 0 && segmentCount >= CYLINDER_MIN_SEGMENTS) {
gd = BASE_NS::make_unique<Geometry::CylinderETS>(radius, height, segmentCount);
} else {
SetBusinessError(ErrorCode::INVALID_ARGUMENTS, "Unable to create CylinderETS: Invalid parameters given");
}
} else {
SetBusinessError(ErrorCode::INVALID_ARGUMENTS, "Unknown type of GeometryDefinition");
return SceneResources::MeshResource({nullptr, nullptr});
}
const std::string name(params.name);
const std::string uri = ExtractUri(params.uri);
return taihe::make_holder<MeshResourceImpl, ::SceneResources::MeshResource>(
std::make_shared<MeshResourceETS>(name, uri, BASE_NS::move(gd)));
}
MeshResourceImpl::MeshResourceImpl(const std::shared_ptr<MeshResourceETS> mrETS)
: SceneResourceImpl(SceneResources::SceneResourceType::key_t::MESH_RESOURCE, mrETS), mrETS_(mrETS)
{}
MeshResourceImpl::~MeshResourceImpl()
{
mrETS_.reset();
}
void MeshResourceImpl::destroy()
{
if (mrETS_) {
mrETS_->Destroy();
mrETS_.reset();
}
}
}