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,const CustomMeshData & data)109 Future<IMesh::Ptr> MeshCreator::Create(const MeshConfig& c, const CustomMeshData& data)
110 {
111 if (auto scene = scene_.lock()) {
112 return scene->AddTask([=] {
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 auto colorData = FillData(data.colors);
127 CORE3D_NS::IMeshBuilder::DataBuffer dummy {};
128
129 builder->SetVertexData(0, positionData, normalData, uvData, dummy, dummy, colorData);
130 builder->CalculateAABB(0, positionData);
131
132 auto indexData = FillData(data.indices);
133 builder->SetIndexData(0, indexData);
134
135 auto ent = builder->CreateMesh(*scene->GetEcsContext().GetNativeEcs());
136 if (!c.name.empty()) {
137 CORE_NS::GetManager<CORE3D_NS::IUriComponentManager>(*scene->GetEcsContext().GetNativeEcs())
138 ->Set(ent, { c.name });
139 CORE_NS::GetManager<CORE3D_NS::INameComponentManager>(*scene->GetEcsContext().GetNativeEcs())
140 ->Set(ent, { c.name });
141 }
142 return CreateMesh(scene, ent);
143 });
144 }
145 return {};
146 }
CreateCube(const MeshConfig & c,float width,float height,float depth)147 Future<IMesh::Ptr> MeshCreator::CreateCube(const MeshConfig& c, float width, float height, float depth)
148 {
149 if (auto scene = scene_.lock()) {
150 return scene->AddTask([=] {
151 auto& util = scene->GetGraphicsContext().GetMeshUtil();
152 auto ent = util.GenerateCubeMesh(
153 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), width, height, depth);
154 return CreateMesh(scene, ent);
155 });
156 }
157 return {};
158 }
CreatePlane(const MeshConfig & c,float width,float depth)159 Future<IMesh::Ptr> MeshCreator::CreatePlane(const MeshConfig& c, float width, float depth)
160 {
161 if (auto scene = scene_.lock()) {
162 return scene->AddTask([=] {
163 auto& util = scene->GetGraphicsContext().GetMeshUtil();
164 auto ent =
165 util.GeneratePlaneMesh(*scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), width, depth);
166 return CreateMesh(scene, ent);
167 });
168 }
169 return {};
170 }
CreateSphere(const MeshConfig & c,float radius,uint32_t rings,uint32_t sectors)171 Future<IMesh::Ptr> MeshCreator::CreateSphere(const MeshConfig& c, float radius, uint32_t rings, uint32_t sectors)
172 {
173 if (auto scene = scene_.lock()) {
174 return scene->AddTask([=] {
175 auto& util = scene->GetGraphicsContext().GetMeshUtil();
176 auto ent = util.GenerateSphereMesh(
177 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), radius, rings, sectors);
178 return CreateMesh(scene, ent);
179 });
180 }
181 return {};
182 }
CreateCone(const MeshConfig & c,float radius,float length,uint32_t sectors)183 Future<IMesh::Ptr> MeshCreator::CreateCone(const MeshConfig& c, float radius, float length, uint32_t sectors)
184 {
185 if (auto scene = scene_.lock()) {
186 return scene->AddTask([=] {
187 auto& util = scene->GetGraphicsContext().GetMeshUtil();
188 auto ent = util.GenerateConeMesh(
189 *scene->GetEcsContext().GetNativeEcs(), c.name, GetMaterial(c), radius, length, sectors);
190 return CreateMesh(scene, ent);
191 });
192 }
193 return {};
194 }
195
196 SCENE_END_NAMESPACE()