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_creator.h"
17
18 #include <scene/ext/intf_ecs_context.h>
19 #include <scene/ext/util.h>
20
21 #include <3d/ecs/components/name_component.h>
22 #include <3d/ecs/components/uri_component.h>
23 #include <3d/implementation_uids.h>
24 #include <3d/render/default_material_constants.h>
25 #include <3d/util/intf_mesh_builder.h>
26 #include <3d/util/intf_mesh_util.h>
27 #include <core/plugin/intf_class_factory.h>
28
SCENE_BEGIN_NAMESPACE()29 SCENE_BEGIN_NAMESPACE()
30
31 bool MeshCreator::Build(const META_NS::IMetadata::Ptr& d)
32 {
33 IInternalScene::Ptr p;
34 if (Super::Build(d)) {
35 p = GetInterfaceBuildArg<IInternalScene>(d, "Scene");
36 scene_ = p;
37 }
38 return p != nullptr;
39 }
40
GetMaterial(const MeshConfig & c)41 static CORE_NS::Entity GetMaterial(const MeshConfig& c)
42 {
43 if (auto i = interface_cast<IEcsObjectAccess>(c.material)) {
44 if (auto obj = i->GetEcsObject()) {
45 return obj->GetEntity();
46 }
47 }
48 return {};
49 }
50
CreateMesh(const IInternalScene::Ptr & scene,CORE_NS::Entity ent)51 static IMesh::Ptr CreateMesh(const IInternalScene::Ptr& scene, CORE_NS::Entity ent)
52 {
53 if (!CORE_NS::EntityUtil::IsValid(ent)) {
54 return nullptr;
55 }
56 auto ecsobj = scene->GetEcsContext().GetEcsObject(ent);
57 if (!ecsobj) {
58 return nullptr;
59 }
60 auto mesh = META_NS::GetObjectRegistry().Create<IMesh>(ClassId::Mesh);
61 if (!mesh) {
62 return nullptr;
63 }
64 if (auto acc = interface_cast<IEcsObjectAccess>(mesh)) {
65 if (!acc->SetEcsObject(ecsobj)) {
66 return nullptr;
67 }
68 }
69 return mesh;
70 }
71
72 template<typename T>
FillData(const BASE_NS::vector<T> & c)73 constexpr static CORE3D_NS::IMeshBuilder::DataBuffer FillData(const BASE_NS::vector<T>& c) noexcept
74 {
75 using namespace BASE_NS;
76 Format format = BASE_FORMAT_UNDEFINED;
77 if constexpr (is_same_v<T, Math::Vec2>) {
78 format = BASE_FORMAT_R32G32_SFLOAT;
79 } else if constexpr (is_same_v<T, Math::Vec3>) {
80 format = BASE_FORMAT_R32G32B32_SFLOAT;
81 } else if constexpr (is_same_v<T, Math::Vec4>) {
82 format = BASE_FORMAT_R32G32B32A32_SFLOAT;
83 } else if constexpr (is_same_v<T, uint16_t>) {
84 format = BASE_FORMAT_R16_UINT;
85 } else if constexpr (is_same_v<T, uint32_t>) {
86 format = BASE_FORMAT_R32_UINT;
87 }
88 return CORE3D_NS::IMeshBuilder::DataBuffer { format, sizeof(T),
89 { reinterpret_cast<const uint8_t*>(c.data()), c.size() * sizeof(T) } };
90 }
91
CreateMeshBuilder(RENDER_NS::IRenderContext & context,const CORE3D_NS::IMeshBuilder::Submesh & submesh)92 static CORE3D_NS::IMeshBuilder::Ptr CreateMeshBuilder(
93 RENDER_NS::IRenderContext& context, const CORE3D_NS::IMeshBuilder::Submesh& submesh)
94 {
95 CORE3D_NS::IMeshBuilder::Ptr builder;
96 RENDER_NS::IShaderManager& shaderManager = context.GetDevice().GetShaderManager();
97 const RENDER_NS::VertexInputDeclarationView vertexInputDeclaration =
98 shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
99 CORE3D_NS::DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
100 builder = CORE_NS::CreateInstance<CORE3D_NS::IMeshBuilder>(context, CORE3D_NS::UID_MESH_BUILDER);
101 builder->Initialize(vertexInputDeclaration, 1);
102
103 builder->AddSubmesh(submesh);
104 builder->Allocate();
105
106 return builder;
107 }
108
Create(const MeshConfig & c,CustomMeshData d)109 Future<IMesh::Ptr> MeshCreator::Create(const MeshConfig& c, CustomMeshData d)
110 {
111 if (auto scene = scene_.lock()) {
112 return scene->AddTask([=, data = BASE_NS::move(d)] {
113 CORE3D_NS::IMeshBuilder::Submesh submesh;
114 submesh.inputAssembly =
115 RENDER_NS::GraphicsState::InputAssembly { false, RENDER_NS::PrimitiveTopology(data.topology) };
116 submesh.material = GetMaterial(c);
117 submesh.vertexCount = static_cast<uint32_t>(data.vertices.size());
118 submesh.indexCount = static_cast<uint32_t>(data.indices.size());
119 submesh.colors = true;
120
121 auto builder = CreateMeshBuilder(scene->GetRenderContext(), submesh);
122
123 auto positionData = FillData(data.vertices);
124 auto normalData = FillData(data.normals);
125 auto uvData = FillData(data.uvs);
126 // Convert from BASE_NS::Color->BASE_NS::Math::Vec4
127 BASE_NS::vector<BASE_NS::Math::Vec4> colors;
128 colors.reserve(data.colors.size());
129 for (auto&& color : data.colors) {
130 colors.emplace_back(color.r, color.g, color.b, color.a);
131 }
132 auto colorData = FillData(colors);
133 CORE3D_NS::IMeshBuilder::DataBuffer dummy {};
134
135 builder->SetVertexData(0, positionData, normalData, uvData, dummy, dummy, colorData);
136 builder->CalculateAABB(0, positionData);
137
138 auto indexData = FillData(data.indices);
139 builder->SetIndexData(0, indexData);
140
141 auto ent = builder->CreateMesh(*scene->GetEcsContext().GetNativeEcs());
142 if (!c.name.empty()) {
143 CORE_NS::GetManager<CORE3D_NS::IUriComponentManager>(*scene->GetEcsContext().GetNativeEcs())
144 ->Set(ent, { c.name });
145 CORE_NS::GetManager<CORE3D_NS::INameComponentManager>(*scene->GetEcsContext().GetNativeEcs())
146 ->Set(ent, { c.name });
147 }
148 return CreateMesh(scene, ent);
149 });
150 }
151 return {};
152 }
CreateCube(const MeshConfig & c,float width,float height,float depth)153 Future<IMesh::Ptr> MeshCreator::CreateCube(const MeshConfig& c, float width, float height, float depth)
154 {
155 if (auto scene = scene_.lock()) {
156 return scene->AddTask([=] {
157 auto& util = scene->GetGraphicsContext().GetMeshUtil();
158 auto ent = util.GenerateCubeMesh(
159 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), width, height, depth);
160 return CreateMesh(scene, ent);
161 });
162 }
163 return {};
164 }
CreatePlane(const MeshConfig & c,float width,float depth)165 Future<IMesh::Ptr> MeshCreator::CreatePlane(const MeshConfig& c, float width, float depth)
166 {
167 if (auto scene = scene_.lock()) {
168 return scene->AddTask([=] {
169 auto& util = scene->GetGraphicsContext().GetMeshUtil();
170 auto ent =
171 util.GeneratePlaneMesh(*scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), width, depth);
172 return CreateMesh(scene, ent);
173 });
174 }
175 return {};
176 }
CreateSphere(const MeshConfig & c,float radius,uint32_t rings,uint32_t sectors)177 Future<IMesh::Ptr> MeshCreator::CreateSphere(const MeshConfig& c, float radius, uint32_t rings, uint32_t sectors)
178 {
179 if (auto scene = scene_.lock()) {
180 return scene->AddTask([=] {
181 auto& util = scene->GetGraphicsContext().GetMeshUtil();
182 auto ent = util.GenerateSphereMesh(
183 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), radius, rings, sectors);
184 return CreateMesh(scene, ent);
185 });
186 }
187 return {};
188 }
CreateCone(const MeshConfig & c,float radius,float length,uint32_t sectors)189 Future<IMesh::Ptr> MeshCreator::CreateCone(const MeshConfig& c, float radius, float length, uint32_t sectors)
190 {
191 if (auto scene = scene_.lock()) {
192 return scene->AddTask([=] {
193 auto& util = scene->GetGraphicsContext().GetMeshUtil();
194 auto ent = util.GenerateConeMesh(
195 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), radius, length, sectors);
196 return CreateMesh(scene, ent);
197 });
198 }
199 return {};
200 }
201
202 SCENE_END_NAMESPACE()