* 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 "mesh_node.h"
#include <3d/ecs/components/mesh_component.h>
#include <3d/util/intf_scene_util.h>
#include <meta/api/make_callback.h>
#include <meta/interface/property/array_property.h>
#include "../ecs_component/entity_owner_component.h"
#include "../mesh/submesh.h"
SCENE_BEGIN_NAMESPACE()
bool MeshNode::SetEcsObject(const IEcsObject::Ptr& o)
{
if (Super::SetEcsObject(o)) {
auto att = GetSelf<META_NS::IAttach>()->GetAttachments<IInternalRenderMesh>();
if (!att.empty()) {
return Init(att.front());
}
}
return false;
}
CORE_NS::Entity MeshNode::CreateEntity(const IInternalScene::Ptr& scene)
{
const auto& context = scene->GetEcsContext();
const auto& ecs = context.GetNativeEcs();
const auto renderMeshManager = CORE_NS::GetManager<CORE3D_NS::IRenderMeshComponentManager>(*ecs);
const auto ownerManager = CORE_NS::GetManager<IEntityOwnerComponentManager>(*ecs);
const auto meshManager = CORE_NS::GetManager<CORE3D_NS::IMeshComponentManager>(*ecs);
if (!renderMeshManager || !meshManager || !ownerManager) {
return {};
}
const auto entity = ecs->GetEntityManager().Create();
renderMeshManager->Create(entity);
const auto handle = renderMeshManager->Write(entity);
if (!handle) {
ecs->GetEntityManager().Destroy(entity);
return {};
}
handle->mesh = ecs->GetEntityManager().Create();
meshManager->Create(handle->mesh);
ownerManager->Create(entity);
const auto ownerHandle = ownerManager->Write(entity);
if (!ownerHandle) {
ecs->GetEntityManager().Destroy(entity);
ecs->GetEntityManager().Destroy(handle->mesh);
return {};
}
context.AddDefaultComponents(entity);
ownerHandle->entity = ecs->GetEntityManager().GetReferenceCounted(handle->mesh);
return entity;
}
bool MeshNode::Init(const IInternalRenderMesh::Ptr& rmesh)
{
auto ent = rmesh->Mesh()->GetValue();
if (!CORE_NS::EntityUtil::IsValid(ent)) {
return false;
}
auto ecsobj = GetInternalScene()->GetEcsContext().GetEcsObject(ent);
auto res = Init(ecsobj);
if (res) {
SetOwnedEntity(ent);
}
return res;
}
bool MeshNode::Init(const IEcsObject::Ptr& ecsobj)
{
if (!ecsobj) {
return false;
}
mesh_ = META_NS::GetObjectRegistry().Create<IMesh>(ClassId::Mesh);
if (!mesh_) {
return false;
}
if (auto acc = interface_cast<IEcsObjectAccess>(mesh_)) {
if (!acc->SetEcsObject(ecsobj)) {
return false;
}
}
if (auto morph = GetAttachments({IMorpher::UID}, false); !morph.empty()) {
Morpher()->SetValue(interface_pointer_cast<IMorpher>(morph.front()));
}
return true;
}
void MeshNode::SetOwnedEntity(CORE_NS::Entity ent)
{
if (auto obj = GetEcsObject()) {
auto scene = obj->GetScene();
if (!scene) {
return;
}
auto ecs = scene->GetEcsContext().GetNativeEcs();
auto ownerManager = CORE_NS::GetManager<IEntityOwnerComponentManager>(*ecs);
if (ownerManager) {
auto nodeEntity = obj->GetEntity();
ownerManager->Create(nodeEntity);
if (auto ownerHandle = ownerManager->Write(nodeEntity)) {
ownerHandle->entity = ecs->GetEntityManager().GetReferenceCounted(ent);
}
}
}
}
Future<bool> MeshNode::SetMesh(const IMesh::Ptr& m)
{
if (auto obj = GetEcsObject()) {
auto scene = obj->GetScene();
if (!scene) {
return {};
}
return scene->AddTaskOrRunDirectly([this, scene, m, weak = BASE_NS::weak_ptr{GetSelf()}] {
auto self = weak.lock();
if (!self) {
return false;
}
IMesh::Ptr mesh = m;
if (auto acc = interface_cast<IMeshAccess>(mesh)) {
mesh = acc->GetMesh().GetResult();
}
if (auto objacc = interface_cast<IEcsObjectAccess>(mesh)) {
if (auto obj = objacc->GetEcsObject()) {
auto att = GetSelf<META_NS::IAttach>()->GetAttachments<IInternalRenderMesh>();
if (!att.empty()) {
auto prop = att.front()->Mesh();
prop->SetValue(obj->GetEntity());
scene->SyncProperty(prop, META_NS::EngineSyncDirection::TO_ENGINE);
mesh_ = mesh;
SetOwnedEntity(obj->GetEntity());
return true;
}
}
}
return false;
});
}
return {};
}
Future<IMesh::Ptr> MeshNode::GetMesh() const
{
if (auto obj = GetEcsObject()) {
auto scene = obj->GetScene();
if (!scene) {
return {};
}
return scene->AddTaskOrRunDirectly(
[this, weak = BASE_NS::weak_ptr{GetSelf()}] { return weak.lock() ? mesh_ : IMesh::Ptr{}; });
}
return {};
}
SCENE_END_NAMESPACE()