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
SCENE_BEGIN_NAMESPACE()21 SCENE_BEGIN_NAMESPACE()
22
23 void Mesh::SetInternalMesh(IInternalMesh::Ptr m)
24 {
25 mesh_ = std::move(m);
26 }
27
OnPropertyChanged(const META_NS::IProperty & p)28 void Mesh::OnPropertyChanged(const META_NS::IProperty& p)
29 {
30 if (p.GetName() == "MaterialOverride") {
31 OnMaterialOverrideChanged();
32 }
33 }
34
GetMeshEcsObject() const35 IEcsObject::Ptr Mesh::GetMeshEcsObject() const
36 {
37 auto comp = interface_cast<IEcsObjectAccess>(mesh_);
38 return comp ? comp->GetEcsObject() : nullptr;
39 }
40
GetSubmeshes() const41 Future<BASE_NS::vector<ISubMesh::Ptr>> Mesh::GetSubmeshes() const
42 {
43 if (auto obj = GetMeshEcsObject()) {
44 if (auto scene = obj->GetScene()) {
45 return scene->AddTask([=] {
46 BASE_NS::vector<ISubMesh::Ptr> res;
47 for (auto&& v : mesh_->SubMeshes()->GetValue()) {
48 auto sm = META_NS::GetObjectRegistry().Create<ISubMesh>(ClassId::SubMesh);
49 if (auto i = interface_cast<IInternalSubMesh>(sm)) {
50 if (i->SetSubMesh(scene->GetEcsContext(), v)) {
51 res.push_back(BASE_NS::move(sm));
52 } else {
53 CORE_LOG_E("Failed to create submesh");
54 }
55 }
56 }
57 return res;
58 });
59 }
60 }
61 return Future<BASE_NS::vector<ISubMesh::Ptr>> {};
62 }
63
SetSubmeshes(const BASE_NS::vector<ISubMesh::Ptr> & submeshes)64 Future<bool> Mesh::SetSubmeshes(const BASE_NS::vector<ISubMesh::Ptr>& submeshes)
65 {
66 const auto obj = GetMeshEcsObject();
67 if (!mesh_ || !obj) {
68 CORE_LOG_E("Unable to set submeshes: Mesh is uninitialized");
69 return Future<bool> {};
70 }
71 auto scene = obj->GetScene();
72 if (!scene) {
73 CORE_LOG_E("Unable to set submeshes: Invalid object");
74 return {};
75 }
76 const auto manager = obj->GetEngineValueManager();
77 if (!manager) {
78 CORE_LOG_E("Unable to set submeshes: No engine value manager");
79 return Future<bool> {};
80 }
81
82 auto componentSubmeshes = ConstructComponentSubmeshes(submeshes);
83 ApplyMaterialOverride(componentSubmeshes, true);
84 mesh_->SubMeshes()->SetValue(componentSubmeshes);
85
86 CORE3D_NS::MinAndMax minMax;
87 for (const auto& submesh : componentSubmeshes) {
88 minMax.minAABB = min(minMax.minAABB, submesh.aabbMin);
89 minMax.maxAABB = max(minMax.maxAABB, submesh.aabbMax);
90 }
91 mesh_->AABBMin()->SetValue(minMax.minAABB);
92 mesh_->AABBMax()->SetValue(minMax.maxAABB);
93
94 return scene->AddTask([=]() -> bool {
95 if (auto s = obj->GetScene()) {
96 s->SyncProperty(mesh_->AABBMin(), META_NS::EngineSyncDirection::TO_ENGINE);
97 s->SyncProperty(mesh_->AABBMax(), META_NS::EngineSyncDirection::TO_ENGINE);
98 s->SyncProperty(mesh_->SubMeshes(), META_NS::EngineSyncDirection::TO_ENGINE);
99 }
100 return true;
101 });
102 }
103
ConstructComponentSubmeshes(const BASE_NS::vector<ISubMesh::Ptr> & submeshes) const104 BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh> Mesh::ConstructComponentSubmeshes(
105 const BASE_NS::vector<ISubMesh::Ptr>& submeshes) const
106 {
107 BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh> componentSubmeshes;
108 componentSubmeshes.reserve(submeshes.size());
109 for (auto&& submesh : submeshes) {
110 if (const auto internalSubMesh = interface_cast<IInternalSubMesh>(submesh)) {
111 componentSubmeshes.emplace_back(internalSubMesh->GetSubMesh());
112 }
113 }
114 return componentSubmeshes;
115 }
116
ApplyMaterialOverride(BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh> & submeshes,bool forceStore)117 void Mesh::ApplyMaterialOverride(BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh>& submeshes, bool forceStore)
118 {
119 const auto materialOverride = interface_cast<IEcsObjectAccess>(MaterialOverride()->GetValue());
120 if (!materialOverride) {
121 return;
122 }
123 std::unique_lock lock { mutex_ };
124 const auto materialOverrideEntity = materialOverride->GetEcsObject()->GetEntity();
125 bool store = forceStore || submeshMaterials_.empty();
126 submeshMaterials_.resize(submeshes.size());
127 size_t i = 0;
128 for (auto&& submesh : submeshes) {
129 if (store) {
130 submeshMaterials_.at(i) = submesh.material;
131 }
132 submesh.material = materialOverrideEntity;
133 i++;
134 }
135 }
136
RestoreOriginalMaterials(BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh> & submeshes)137 void Mesh::RestoreOriginalMaterials(BASE_NS::vector<CORE3D_NS::MeshComponent::Submesh>& submeshes)
138 {
139 std::unique_lock lock { mutex_ };
140 if (!submeshMaterials_.empty()) {
141 if (submeshes.size() != submeshMaterials_.size()) {
142 CORE_LOG_W("submesh size not matching saved submesh materials?!");
143 }
144 size_t i = 0;
145 for (auto&& submesh : submeshes) {
146 submesh.material = submeshMaterials_.at(i);
147 ++i;
148 }
149 submeshMaterials_.clear();
150 }
151 }
152
OnMaterialOverrideChanged()153 void Mesh::OnMaterialOverrideChanged()
154 {
155 auto material = META_NS::GetValue(MaterialOverride());
156 auto p = mesh_->SubMeshes().GetLockedAccess();
157 auto values = p->GetValue();
158 if (material) {
159 ApplyMaterialOverride(values);
160 } else {
161 RestoreOriginalMaterials(values);
162 }
163 p->SetValue(values);
164 }
165
SetEcsObject(const IEcsObject::Ptr & obj)166 bool Mesh::SetEcsObject(const IEcsObject::Ptr& obj)
167 {
168 if (Super::SetEcsObject(obj)) {
169 if (auto att = GetSelf<META_NS::IAttach>()) {
170 if (auto attc = att->GetAttachmentContainer(false)) {
171 if (auto c = attc->FindByName<IInternalMesh>("MeshComponent")) {
172 SetInternalMesh(c);
173 }
174 }
175 }
176 if (!mesh_) {
177 auto p = META_NS::GetObjectRegistry().Create<IInternalMesh>(ClassId::MeshComponent);
178 if (auto acc = interface_cast<IEcsObjectAccess>(p)) {
179 if (acc->SetEcsObject(obj)) {
180 SetInternalMesh(p);
181 if (auto scene = obj->GetScene()) {
182 meshEntity_ = scene->GetEcsContext().GetEntityReference(obj->GetEntity());
183 }
184 }
185 }
186 }
187 }
188 return mesh_ != nullptr;
189 }
190
CreateEntity(const IInternalScene::Ptr & scene)191 CORE_NS::Entity Mesh::CreateEntity(const IInternalScene::Ptr& scene)
192 {
193 const auto& ecs = scene->GetEcsContext().GetNativeEcs();
194 const auto meshManager = CORE_NS::GetManager<CORE3D_NS::IMeshComponentManager>(*ecs);
195 if (!meshManager) {
196 return {};
197 }
198 auto ent = ecs->GetEntityManager().Create();
199 meshManager->Create(ent);
200 return ent;
201 }
202
203 SCENE_END_NAMESPACE()