• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "mesh.h"
17 
18 #include <3d/ecs/components/mesh_component.h>
19 #include <3d/util/intf_picking.h>
20 
21 #include <meta/api/make_callback.h>
22 
23 #include "util_interfaces.h"
24 
SCENE_BEGIN_NAMESPACE()25 SCENE_BEGIN_NAMESPACE()
26 
27 void Mesh::Destroy()
28 {
29     if (META_NS::ArrayProperty<ISubMesh::Ptr> arr { GetProperty("SubMeshes", META_NS::MetadataQuery::EXISTING) }) {
30         for (auto&& v : arr->GetValue()) {
31             if (auto i = interface_cast<META_NS::INotifyOnChange>(v)) {
32                 i->OnChanged()->RemoveHandler(uintptr_t(this));
33             }
34         }
35     }
36     Super::Destroy();
37 }
38 
SetInternalMesh(IInternalMesh::Ptr m)39 void Mesh::SetInternalMesh(IInternalMesh::Ptr m)
40 {
41     submeshEvent_.Unsubscribe();
42     mesh_ = std::move(m);
43     if (mesh_) {
44         submeshEvent_.Subscribe<META_NS::IOnChanged>(
45             mesh_->SubMeshes()->OnChanged(), [this] { UpdateSubmeshes(SubMeshes()); });
46     }
47 }
48 
GetMeshEcsObject() const49 IEcsObject::Ptr Mesh::GetMeshEcsObject() const
50 {
51     auto comp = interface_cast<IEcsObjectAccess>(mesh_);
52     return comp ? comp->GetEcsObject() : nullptr;
53 }
54 
SetEcsObject(const IEcsObject::Ptr & obj)55 bool Mesh::SetEcsObject(const IEcsObject::Ptr& obj)
56 {
57     if (Super::SetEcsObject(obj)) {
58         if (auto att = GetSelf<META_NS::IAttach>()) {
59             if (auto attc = att->GetAttachmentContainer(false)) {
60                 if (auto c = attc->FindByName<IInternalMesh>("MeshComponent")) {
61                     SetInternalMesh(c);
62                 }
63             }
64         }
65         if (!mesh_) {
66             auto p = META_NS::GetObjectRegistry().Create<IInternalMesh>(ClassId::MeshComponent);
67             if (auto acc = interface_cast<IEcsObjectAccess>(p)) {
68                 if (acc->SetEcsObject(obj)) {
69                     SetInternalMesh(p);
70                     if (auto scene = obj->GetScene()) {
71                         auto ecs = scene->GetEcsContext().GetNativeEcs();
72                         meshEntity_ = ecs->GetEntityManager().GetReferenceCounted(obj->GetEntity());
73                     }
74                 }
75             }
76         }
77     }
78     return mesh_ != nullptr;
79 }
80 
CreateEntity(const IInternalScene::Ptr & scene)81 CORE_NS::Entity Mesh::CreateEntity(const IInternalScene::Ptr& scene)
82 {
83     const auto& ecs = scene->GetEcsContext().GetNativeEcs();
84     const auto meshManager = CORE_NS::GetManager<CORE3D_NS::IMeshComponentManager>(*ecs);
85     if (!meshManager) {
86         return {};
87     }
88     auto ent = ecs->GetEntityManager().Create();
89     meshManager->Create(ent);
90     return ent;
91 }
92 
InitDynamicProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)93 bool Mesh::InitDynamicProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
94 {
95     if (p->GetName() == "SubMeshes") {
96         return UpdateSubmeshes(META_NS::ArrayProperty<ISubMesh::Ptr>(p));
97     }
98     return false;
99 }
100 
RecalculateAABB()101 void Mesh::RecalculateAABB()
102 {
103     CORE3D_NS::MinAndMax minMax;
104     for (const auto& submesh : SubMeshes()->GetValue()) {
105         minMax.minAABB = min(minMax.minAABB, submesh->AABBMin()->GetValue());
106         minMax.maxAABB = max(minMax.maxAABB, submesh->AABBMax()->GetValue());
107     }
108     mesh_->AABBMin()->SetValue(minMax.minAABB);
109     mesh_->AABBMax()->SetValue(minMax.maxAABB);
110 }
111 
UpdateSubmeshes(META_NS::ArrayProperty<ISubMesh::Ptr> prop)112 bool Mesh::UpdateSubmeshes(META_NS::ArrayProperty<ISubMesh::Ptr> prop)
113 {
114     if (!prop) {
115         return false;
116     }
117     auto& r = META_NS::GetObjectRegistry();
118     BASE_NS::vector<ISubMesh::Ptr> orig = prop->GetValue();
119     BASE_NS::vector<ISubMesh::Ptr> subs;
120     auto msubs = mesh_->SubMeshes()->GetValue();
121     for (size_t i = 0; i != msubs.size(); ++i) {
122         ISubMesh::Ptr t;
123         if (i < orig.size()) {
124             t = orig[i];
125         } else {
126             t = r.Create<ISubMesh>(ClassId::SubMesh);
127             if (auto si = interface_cast<IArrayElementIndex>(t)) {
128                 si->SetIndex(i);
129             }
130             if (auto i = interface_cast<META_NS::INotifyOnChange>(t)) {
131                 i->OnChanged()->AddHandler(
132                     META_NS::MakeCallback<META_NS::IOnChanged>([this] { RecalculateAABB(); }), uintptr_t(this));
133             }
134         }
135         if (auto access = interface_cast<IEcsObjectAccess>(t)) {
136             access->SetEcsObject(GetEcsObject());
137             subs.push_back(t);
138         } else {
139             CORE_LOG_E("Failed to create submesh for mesh");
140             return false;
141         }
142     }
143     if (orig.size() > subs.size()) {
144         for (auto it = orig.begin() + subs.size(); it != orig.end(); ++it) {
145             if (auto i = interface_cast<META_NS::INotifyOnChange>(*it)) {
146                 i->OnChanged()->RemoveHandler(uintptr_t(this));
147             }
148         }
149     }
150     RefreshSubmeshes(subs);
151     prop->SetValue(subs);
152     return true;
153 }
RefreshSubmeshes(const BASE_NS::vector<ISubMesh::Ptr> & subs)154 void Mesh::RefreshSubmeshes(const BASE_NS::vector<ISubMesh::Ptr>& subs)
155 {
156     if (auto scene = GetInternalScene()) {
157         scene
158             ->AddTask([&] {
159                 for (auto&& s : subs) {
160                     if (auto m = interface_cast<META_NS::IMetadata>(s)) {
161                         for (auto&& p : m->GetProperties()) {
162                             scene->SyncProperty(p, META_NS::EngineSyncDirection::AUTO);
163                         }
164                     }
165                 }
166             })
167             .Wait();
168     }
169 }
170 SCENE_END_NAMESPACE()
171