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