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_util.h"
17  
18  #include <algorithm>
19  
20  #include <3d/ecs/components/material_component.h>
21  #include <3d/ecs/components/name_component.h>
22  #include <3d/ecs/components/render_mesh_component.h>
23  #include <3d/ecs/components/uri_component.h>
24  #include <3d/ecs/systems/intf_node_system.h>
25  #include <3d/implementation_uids.h>
26  #include <3d/render/default_material_constants.h>
27  #include <3d/util/intf_mesh_builder.h>
28  #include <base/containers/vector.h>
29  #include <base/math/quaternion_util.h>
30  #include <base/math/vector.h>
31  #include <core/ecs/intf_ecs.h>
32  #include <core/intf_engine.h>
33  #include <core/log.h>
34  #include <core/namespace.h>
35  #include <core/plugin/intf_class_factory.h>
36  #include <render/device/intf_shader_manager.h>
37  #include <render/implementation_uids.h>
38  #include <render/intf_render_context.h>
39  
40  #include "util/uri_lookup.h"
41  
42  CORE3D_BEGIN_NAMESPACE()
43  using namespace BASE_NS;
44  using namespace CORE_NS;
45  using namespace RENDER_NS;
46  
47  namespace {
48  constexpr Math::Vec3 PLANE_NORM[6u] = {
49      Math::Vec3(0.0f, 1.0f, 0.0f),
50      Math::Vec3(0.0f, 1.0f, 0.0f),
51      Math::Vec3(0.0f, 1.0f, 0.0f),
52  
53      Math::Vec3(0.0f, 1.0f, 0.0f),
54      Math::Vec3(0.0f, 1.0f, 0.0f),
55      Math::Vec3(0.0f, 1.0f, 0.0f),
56  };
57  
58  constexpr Math::Vec2 PLANE_UV[6u] = {
59      Math::Vec2(1.0f, 1.0f),
60      Math::Vec2(1.0f, 0.0f),
61      Math::Vec2(0.0f, 1.0f),
62  
63      Math::Vec2(1.0f, 0.0f),
64      Math::Vec2(0.0f, 0.0f),
65      Math::Vec2(0.0f, 1.0f),
66  };
67  
68  constexpr uint16_t PLANE_IND[] = { 0u, 1u, 2u, 3u, 4u, 5u };
69  
70  constexpr Math::Vec3 CUBE_POS[8u] = {
71      Math::Vec3(-0.5f, -0.5f, -0.5f), //
72      Math::Vec3(0.5f, -0.5f, -0.5f),  //
73      Math::Vec3(0.5f, 0.5f, -0.5f),   //
74      Math::Vec3(-0.5f, 0.5f, -0.5f),  //
75      Math::Vec3(-0.5f, -0.5f, 0.5f),  //
76      Math::Vec3(0.5f, -0.5f, 0.5f),   //
77      Math::Vec3(0.5f, 0.5f, 0.5f),    //
78      Math::Vec3(-0.5f, 0.5f, 0.5f)    //
79  };
80  
81  constexpr Math::Vec2 CUBE_UV[4u] = { Math::Vec2(1.0f, 1.0f), Math::Vec2(0.0f, 1.0f), Math::Vec2(0.0f, 0.0f),
82      Math::Vec2(1.0f, 0.0f) };
83  
84  constexpr uint16_t CUBE_INDICES[6u * 6u] = {
85      0, 3, 1, 3, 2, 1, //
86      1, 2, 5, 2, 6, 5, //
87      5, 6, 4, 6, 7, 4, //
88      4, 7, 0, 7, 3, 0, //
89      3, 7, 2, 7, 6, 2, //
90      4, 0, 5, 0, 1, 5  //
91  };
92  
93  constexpr uint32_t CUBE_UV_INDICES[6u] = { 0, 3, 1, 3, 2, 1 };
94  
95  constexpr float TWO_PI = Math::PI * 2.0f;
96  
97  template<typename IndexType>
98  struct Geometry {
99      vector<Math::Vec3>& vertices;
100      vector<Math::Vec3>& normals;
101      vector<Math::Vec2>& uvs;
102      vector<IndexType>& indices;
103  };
104  
GenerateCubeGeometry(float width,float height,float depth,Geometry<uint16_t> geometry)105  void GenerateCubeGeometry(float width, float height, float depth, Geometry<uint16_t> geometry)
106  {
107      vector<Math::Vec3>& vertices = geometry.vertices;
108      vector<Math::Vec3>& normals = geometry.normals;
109      vector<Math::Vec2>& uvs = geometry.uvs;
110      vector<uint16_t>& indices = geometry.indices;
111  
112      vertices.reserve(countof(CUBE_INDICES));
113      normals.reserve(countof(CUBE_INDICES));
114      uvs.reserve(countof(CUBE_INDICES));
115      indices.reserve(countof(CUBE_INDICES));
116  
117      constexpr size_t triangleCount = countof(CUBE_INDICES) / 3u;
118      for (size_t i = 0; i < triangleCount; ++i) {
119          const size_t vertexIndex = i * 3u;
120  
121          const Math::Vec3 v0 = CUBE_POS[CUBE_INDICES[vertexIndex + 0u]];
122          const Math::Vec3 v1 = CUBE_POS[CUBE_INDICES[vertexIndex + 1u]];
123          const Math::Vec3 v2 = CUBE_POS[CUBE_INDICES[vertexIndex + 2u]];
124  
125          vertices.emplace_back(v0.x * width, v0.y * height, v0.z * depth);
126          vertices.emplace_back(v1.x * width, v1.y * height, v1.z * depth);
127          vertices.emplace_back(v2.x * width, v2.y * height, v2.z * depth);
128  
129          const Math::Vec3 normal = Math::Normalize(Math::Cross((v1 - v0), (v2 - v0)));
130          normals.insert(normals.end(), 3u, normal);
131  
132          uvs.emplace_back(
133              CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 0u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 0u) % 6u]].y);
134          uvs.emplace_back(
135              CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 1u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 1u) % 6u]].y);
136          uvs.emplace_back(
137              CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 2u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 2u) % 6u]].y);
138      }
139  
140      for (uint16_t i = 0u; i < countof(CUBE_INDICES); ++i) {
141          indices.push_back(i);
142      }
143  }
144  
GenerateSphereGeometry(float radius,uint32_t rings,uint32_t sectors,Geometry<uint32_t> geometry)145  void GenerateSphereGeometry(float radius, uint32_t rings, uint32_t sectors, Geometry<uint32_t> geometry)
146  {
147      vector<Math::Vec3>& vertices = geometry.vertices;
148      vector<Math::Vec3>& normals = geometry.normals;
149      vector<Math::Vec2>& uvs = geometry.uvs;
150      vector<uint32_t>& indices = geometry.indices;
151  
152      const size_t maxVertexCount = rings * sectors;
153      const size_t maxIndexCount = (rings - 1) * sectors * 6u;
154  
155      vertices.reserve(maxVertexCount);
156      normals.reserve(maxVertexCount);
157      uvs.reserve(maxVertexCount);
158      indices.reserve(maxIndexCount);
159  
160      const float r = 1.0f / static_cast<float>(rings - 1);
161      const float s = 1.0f / static_cast<float>(sectors - 1);
162  
163      constexpr float pi = Math::PI;
164      constexpr float halfPi = Math::PI * 0.5f;
165  
166      for (uint32_t ring = 0; ring < rings; ++ring) {
167          const auto ringF = static_cast<float>(ring);
168          for (uint32_t sector = 0; sector < sectors; ++sector) {
169              const auto sectorF = static_cast<float>(sector);
170              const float y = Math::sin(-halfPi + pi * ringF * r);
171              const float x = Math::cos(TWO_PI * sectorF * s) * Math::sin(pi * ringF * r);
172              const float z = Math::sin(TWO_PI * sectorF * s) * Math::sin(pi * ringF * r);
173  
174              vertices.emplace_back(x * radius, y * radius, z * radius);
175              normals.emplace_back(x, y, z);
176              uvs.emplace_back(sectorF * s, ringF * r);
177  
178              if (ring < rings - 1) {
179                  const uint32_t curRow = ring * sectors;
180                  const uint32_t nextRow = (ring + 1) * sectors;
181                  const uint32_t nextS = (sector + 1) % sectors;
182  
183                  indices.push_back(curRow + sector);
184                  indices.push_back(nextRow + sector);
185                  indices.push_back(nextRow + nextS);
186  
187                  indices.push_back(curRow + sector);
188                  indices.push_back(nextRow + nextS);
189                  indices.push_back(curRow + nextS);
190              }
191          }
192      }
193  }
194  
GenerateConeCap(float radius,float length,uint32_t sectors,Geometry<uint32_t> geometry,const vector<Math::Vec2> & unitCoords)195  void GenerateConeCap(
196      float radius, float length, uint32_t sectors, Geometry<uint32_t> geometry, const vector<Math::Vec2>& unitCoords)
197  {
198      vector<Math::Vec3>& vertices = geometry.vertices;
199      vector<Math::Vec3>& normals = geometry.normals;
200      vector<Math::Vec2>& uvs = geometry.uvs;
201      vector<uint32_t>& indices = geometry.indices;
202  
203      // Already generated vertices: tip + sectors
204      uint32_t startVertex = 1U + sectors;
205  
206      // Cap center vert.
207      const uint32_t bottomIndex = startVertex;
208      vertices.emplace_back(0.0f, 0.0f, length);
209      normals.emplace_back(0.0f, 0.0f, 1.0f);
210      uvs.emplace_back(0.5f, 0.5f);
211  
212      ++startVertex;
213  
214      // Cap ring and triangles.
215      for (uint32_t idx = 0; idx < sectors; ++idx) {
216          const uint32_t vertexIndex = startVertex + idx;
217  
218          const Math::Vec2& coords = unitCoords[idx];
219  
220          vertices.emplace_back(coords.x * radius, coords.y * radius, length);
221          normals.emplace_back(0.0f, 0.0f, 1.0f);
222  
223          float uvx = (coords.x + 1.0f) * 0.5f;
224          float uvy = 1.0f - (coords.y + 1.0f) * 0.5f;
225          uvs.emplace_back(uvx, uvy);
226  
227          const uint32_t nextVertexIndex = startVertex + ((idx + 1) % sectors);
228  
229          indices.push_back(vertexIndex);
230          indices.push_back(nextVertexIndex);
231          indices.push_back(bottomIndex);
232      }
233  }
234  
GenerateConeGeometry(float radius,float length,uint32_t sectors,Geometry<uint32_t> geometry)235  void GenerateConeGeometry(float radius, float length, uint32_t sectors, Geometry<uint32_t> geometry)
236  {
237      vector<Math::Vec3>& vertices = geometry.vertices;
238      vector<Math::Vec3>& normals = geometry.normals;
239      vector<Math::Vec2>& uvs = geometry.uvs;
240      vector<uint32_t>& indices = geometry.indices;
241  
242      const float s = (sectors > 0U) ? (1.0f / static_cast<float>(sectors)) : 1.0f;
243  
244      const size_t maxVertexCount = (2 * static_cast<size_t>(sectors)) + 2u;
245      const size_t maxIndexCount = static_cast<size_t>(sectors) * 6u;
246  
247      vertices.reserve(maxVertexCount);
248      normals.reserve(maxVertexCount);
249      uvs.reserve(maxVertexCount);
250      indices.reserve(maxIndexCount);
251  
252      vector<Math::Vec2> unitCoords;
253      unitCoords.reserve(sectors);
254  
255      vertices.emplace_back(0.0f, 0.0f, 0.0f);
256      normals.emplace_back(0.0f, 0.0f, -1.0f);
257      uvs.emplace_back(0.5f, 0.5f);
258  
259      // Bottom ring vertices and side triangles, with given radius
260      const uint32_t startVertex = 1U;
261      for (uint32_t idx = 0; idx < sectors; ++idx) {
262          const auto idxF = static_cast<float>(idx);
263          const float x = Math::cos(idxF * s * TWO_PI);
264          const float y = Math::sin(idxF * s * TWO_PI);
265          unitCoords.emplace_back(x, y);
266  
267          vertices.emplace_back(x * radius, y * radius, length);
268          normals.emplace_back(x, y, 0.f);
269  
270          float uvx = (x + 1.0f) * 0.5f;
271          float uvy = 1.0f - (y + 1.0f) * 0.5f;
272          uvs.emplace_back(uvx, uvy);
273  
274          const uint32_t v0 = 0;
275          const uint32_t v1 = startVertex + idx;
276          if (sectors == 0) {
277              return;
278          }
279          const uint32_t v2 = startVertex + ((idx + 1) % sectors);
280  
281          indices.push_back(v0);
282          indices.push_back(v2);
283          indices.push_back(v1);
284      }
285  
286      constexpr bool generateCapping = true;
287      if constexpr (generateCapping) {
288          GenerateConeCap(radius, length, sectors, geometry, unitCoords);
289      }
290  }
291  
GenerateTorusSlices(float minorRadius,uint32_t minorSectors,float minorStep)292  vector<Math::Vec3> GenerateTorusSlices(float minorRadius, uint32_t minorSectors, float minorStep)
293  {
294      vector<Math::Vec3> tubeSlice;
295      tubeSlice.reserve(minorSectors);
296      for (uint32_t tube = 0; tube < minorSectors; tube++) {
297          const float minorRadians = static_cast<float>(tube) * minorStep;
298          const float x = 0.0f;
299          const float y = Math::cos(minorRadians) * minorRadius;
300          const float z = Math::sin(minorRadians) * minorRadius;
301          tubeSlice.emplace_back(x, y, z);
302      }
303      return tubeSlice;
304  }
305  
GenerateTorusGeometry(float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors,Geometry<uint32_t> geometry)306  void GenerateTorusGeometry(
307      float majorRadius, float minorRadius, uint32_t majorSectors, uint32_t minorSectors, Geometry<uint32_t> geometry)
308  {
309      vector<Math::Vec3>& vertices = geometry.vertices;
310      vector<Math::Vec3>& normals = geometry.normals;
311      vector<Math::Vec2>& uvs = geometry.uvs;
312      vector<uint32_t>& indices = geometry.indices;
313  
314      const float majorStep = TWO_PI / static_cast<float>(majorSectors);
315      const float minorStep = TWO_PI / static_cast<float>(minorSectors);
316  
317      const size_t maxVertexCount = static_cast<size_t>(majorSectors) * static_cast<size_t>(minorSectors);
318      const size_t maxIndexCount = maxVertexCount * 6u;
319  
320      vertices.reserve(maxVertexCount);
321      normals.reserve(maxVertexCount);
322      uvs.reserve(maxVertexCount);
323      indices.reserve(maxIndexCount);
324  
325      const vector<Math::Vec3> tubeSlice = GenerateTorusSlices(minorRadius, minorSectors, minorStep);
326  
327      uint32_t currentVertexIndex = 0;
328      for (uint32_t ring = 0; ring < majorSectors; ring++) {
329          const float majorRadians = static_cast<float>(ring) * majorStep;
330          const auto rotation = Math::AngleAxis(majorRadians, { 0.0f, 1.0f, 0.0f });
331          const auto translation = Math::Vec3(0.0f, 0.0f, 1.0f) * majorRadius;
332  
333          for (uint32_t vertexIndex = 0; vertexIndex < minorSectors; vertexIndex++) {
334              const auto& ringVertex = tubeSlice[vertexIndex];
335  
336              const auto tubeCenter = rotation * translation;
337  
338              vertices.push_back(rotation * ringVertex + tubeCenter);
339  
340              normals.push_back(Math::Normalize(rotation * ringVertex));
341  
342              const float minorRadians = static_cast<float>(vertexIndex) * minorStep;
343              const float tx = 1.0f - Math::abs(majorRadians / TWO_PI * 2.0f - 1.0f);
344              const float ty = 1.0f - Math::abs(minorRadians / TWO_PI * 2.0f - 1.0f);
345              uvs.emplace_back(tx, ty);
346  
347              const uint32_t i0 = currentVertexIndex;
348              const uint32_t i1 = (i0 + 1) % maxVertexCount;
349              const uint32_t i2 = (i0 + minorSectors) % maxVertexCount;
350              const uint32_t i3 = (i2 + 1) % maxVertexCount;
351  
352              indices.push_back(i0);
353              indices.push_back(i1);
354              indices.push_back(i2);
355  
356              indices.push_back(i1);
357              indices.push_back(i3);
358              indices.push_back(i2);
359  
360              currentVertexIndex++;
361          }
362      }
363  }
364  } // namespace
365  
366  template<typename IndexType>
CalculateTangentImpl(const array_view<const IndexType> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> & outTangents)367  void CalculateTangentImpl(const array_view<const IndexType>& indices, const array_view<const Math::Vec3>& positions,
368      const array_view<const Math::Vec3>& normals, const array_view<const Math::Vec2>& uvs,
369      array_view<Math::Vec4>& outTangents)
370  {
371      // http://www.terathon.com/code/tangent.html
372      vector<Math::Vec3> tan(positions.size(), { 0, 0, 0 });
373      vector<Math::Vec3> bitan(positions.size(), { 0, 0, 0 });
374  
375      for (size_t i = 0; i < indices.size(); i += 3u) {
376          const IndexType aa = indices[i + 0u];
377          const IndexType bb = indices[i + 1u];
378          const IndexType cc = indices[i + 2u];
379  
380          const Math::Vec2& uv1 = uvs[aa];
381          const Math::Vec2& uv2 = uvs[bb];
382          const Math::Vec2& uv3 = uvs[cc];
383  
384          const auto st1 = uv2 - uv1;
385          const auto st2 = uv3 - uv1;
386  
387          auto d = Math::Cross(st1, st2);
388          if (Math::abs(d) < Math::EPSILON) {
389              d = Math::EPSILON;
390          }
391          const float r = 1.0f / d;
392  
393          const Math::Vec3& v1 = positions[aa];
394          const Math::Vec3& v2 = positions[bb];
395          const Math::Vec3& v3 = positions[cc];
396  
397          const auto e1 = v2 - v1;
398          const auto e2 = v3 - v1;
399  
400          const Math::Vec3 sdir { (e1 * st2.y - e2 * st1.y) * r };
401          tan[aa] += sdir;
402          tan[bb] += sdir;
403          tan[cc] += sdir;
404  
405          const Math::Vec3 tdir { (e2 * st1.x - e1 * st2.x) * r };
406  
407          bitan[aa] += tdir;
408          bitan[bb] += tdir;
409          bitan[cc] += tdir;
410      }
411  
412      for (size_t i = 0; i < positions.size(); i++) {
413          const Math::Vec3& n = normals[i];
414          const Math::Vec3& t = tan[i];
415  
416          // Gram-Schmidt orthogonalize
417          const Math::Vec3 tmp = Math::Normalize(t - n * Math::Dot(n, t));
418  
419          // Calculate handedness
420          const float w = (Math::Dot(Math::Cross(n, t), bitan[i]) < 0.0F) ? 1.0F : -1.0F;
421  
422          outTangents[i] = Math::Vec4(tmp.x, tmp.y, tmp.z, w);
423      }
424  }
425  
CalculateTangents(const array_view<const uint32_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)426  void MeshUtil::CalculateTangents(const array_view<const uint32_t>& indices,
427      const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
428      const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
429  {
430      CalculateTangentImpl<uint32_t>(indices, positions, normals, uvs, outTangents);
431  }
432  
CalculateTangents(const array_view<const uint16_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)433  void MeshUtil::CalculateTangents(const array_view<const uint16_t>& indices,
434      const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
435      const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
436  {
437      CalculateTangentImpl<uint16_t>(indices, positions, normals, uvs, outTangents);
438  }
439  
CalculateTangents(const array_view<const uint8_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)440  void MeshUtil::CalculateTangents(const array_view<const uint8_t>& indices,
441      const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
442      const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
443  {
444      CalculateTangentImpl<uint8_t>(indices, positions, normals, uvs, outTangents);
445  }
446  
447  template<typename T>
FillData(array_view<const T> c)448  constexpr inline IMeshBuilder::DataBuffer FillData(array_view<const T> c) noexcept
449  {
450      Format format = BASE_FORMAT_UNDEFINED;
451      if constexpr (is_same_v<T, Math::Vec2>) {
452          format = BASE_FORMAT_R32G32_SFLOAT;
453      } else if constexpr (is_same_v<T, Math::Vec3>) {
454          format = BASE_FORMAT_R32G32B32_SFLOAT;
455      } else if constexpr (is_same_v<T, Math::Vec4>) {
456          format = BASE_FORMAT_R32G32B32A32_SFLOAT;
457      } else if constexpr (is_same_v<T, uint16_t>) {
458          format = BASE_FORMAT_R16_UINT;
459      } else if constexpr (is_same_v<T, uint32_t>) {
460          format = BASE_FORMAT_R32_UINT;
461      }
462      return IMeshBuilder::DataBuffer { format, sizeof(T),
463          { reinterpret_cast<const uint8_t*>(c.data()), c.size() * sizeof(T) } };
464  }
465  
466  template<typename T, size_t N>
FillData(const T (& c)[N])467  constexpr inline IMeshBuilder::DataBuffer FillData(const T (&c)[N]) noexcept
468  {
469      return FillData(array_view(c, N));
470  }
471  
472  template<typename T>
FillData(const vector<T> & c)473  constexpr inline IMeshBuilder::DataBuffer FillData(const vector<T>& c) noexcept
474  {
475      return FillData(array_view<const T> { c });
476  }
477  
GeneratePlaneMesh(const IEcs & ecs,const string_view name,Entity material,float width,float depth)478  Entity MeshUtil::GeneratePlaneMesh(const IEcs& ecs, const string_view name, Entity material, float width, float depth)
479  {
480      const float extentX = width * 0.5f;
481      const float extentZ = depth * 0.5f;
482  
483      const Math::Vec3 pos[6u] = {
484          Math::Vec3(-extentX, 0.0f, -extentZ),
485          Math::Vec3(-extentX, 0.0f, extentZ),
486          Math::Vec3(extentX, 0.0f, -extentZ),
487  
488          Math::Vec3(-extentX, 0.0f, extentZ),
489          Math::Vec3(extentX, 0.0f, extentZ),
490          Math::Vec3(extentX, 0.0f, -extentZ),
491      };
492      vector<Math::Vec4> tangents(countof(pos));
493      {
494          constexpr auto indicesView = array_view(PLANE_IND);
495          const auto positionsView = array_view(pos);
496          constexpr auto normalsView = array_view(PLANE_NORM);
497          constexpr auto uvsView = array_view(PLANE_UV);
498  
499          CalculateTangents(indicesView, positionsView, normalsView, uvsView, tangents);
500      }
501  
502      IMeshBuilder::Submesh submesh;
503      submesh.material = material;
504      submesh.vertexCount = 6u;
505      submesh.indexCount = 6u;
506      submesh.indexType = CORE_INDEX_TYPE_UINT16;
507      submesh.tangents = true;
508  
509      auto builder = InitializeBuilder(submesh);
510  
511      auto positionData = FillData(pos);
512      auto normalData = FillData(PLANE_NORM);
513      auto uvData = FillData(PLANE_UV);
514      auto tangentData = FillData(tangents);
515      IMeshBuilder::DataBuffer dummy {};
516      builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
517  
518      builder->CalculateAABB(0, positionData);
519  
520      auto indices = FillData(PLANE_IND);
521      builder->SetIndexData(0, indices);
522  
523      return CreateMesh(ecs, *builder, name);
524  }
525  
GenerateSphereMesh(const IEcs & ecs,const string_view name,Entity material,float radius,uint32_t rings,uint32_t sectors)526  Entity MeshUtil::GenerateSphereMesh(
527      const IEcs& ecs, const string_view name, Entity material, float radius, uint32_t rings, uint32_t sectors)
528  {
529      vector<Math::Vec3> vertices;
530      vector<Math::Vec3> normals;
531      vector<Math::Vec2> uvs;
532      vector<uint32_t> indices;
533      GenerateSphereGeometry(radius, rings, sectors, { vertices, normals, uvs, indices });
534  
535      vector<Math::Vec4> tangents(vertices.size());
536      CalculateTangents(indices, vertices, normals, uvs, tangents);
537  
538      IMeshBuilder::Submesh submesh;
539      submesh.material = material;
540      submesh.vertexCount = static_cast<uint32_t>(vertices.size());
541      submesh.indexCount = static_cast<uint32_t>(indices.size());
542      submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
543      submesh.tangents = true;
544  
545      auto builder = InitializeBuilder(submesh);
546  
547      auto positionData = FillData(vertices);
548      auto normalData = FillData(normals);
549      auto uvData = FillData(uvs);
550      auto tangentData = FillData(tangents);
551      IMeshBuilder::DataBuffer dummy {};
552      builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
553  
554      builder->CalculateAABB(0, positionData);
555  
556      auto indexData = FillData(indices);
557      builder->SetIndexData(0, indexData);
558  
559      return CreateMesh(ecs, *builder, name);
560  }
561  
GenerateConeMesh(const IEcs & ecs,const string_view name,Entity material,float radius,float length,uint32_t sectors)562  Entity MeshUtil::GenerateConeMesh(
563      const IEcs& ecs, const string_view name, Entity material, float radius, float length, uint32_t sectors)
564  {
565      vector<Math::Vec3> vertices;
566      vector<Math::Vec3> normals;
567      vector<Math::Vec2> uvs;
568      vector<uint32_t> indices;
569      GenerateConeGeometry(radius, length, sectors, { vertices, normals, uvs, indices });
570  
571      IMeshBuilder::Submesh submesh;
572      submesh.material = material;
573      submesh.vertexCount = static_cast<uint32_t>(vertices.size());
574      submesh.indexCount = static_cast<uint32_t>(indices.size());
575      submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
576      submesh.tangents = true;
577  
578      vector<Math::Vec4> tangents(vertices.size());
579      CalculateTangents(indices, vertices, normals, uvs, tangents);
580  
581      auto builder = InitializeBuilder(submesh);
582  
583      auto positionData = FillData(vertices);
584      auto normalData = FillData(normals);
585      auto uvData = FillData(uvs);
586      auto tangentData = FillData(tangents);
587      IMeshBuilder::DataBuffer dummy {};
588      builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
589  
590      builder->CalculateAABB(0, positionData);
591  
592      auto indexData = FillData(indices);
593      builder->SetIndexData(0, indexData);
594  
595      return CreateMesh(ecs, *builder, name);
596  }
597  
GenerateTorusMesh(const IEcs & ecs,const string_view name,Entity material,float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors)598  Entity MeshUtil::GenerateTorusMesh(const IEcs& ecs, const string_view name, Entity material, float majorRadius,
599      float minorRadius, uint32_t majorSectors, uint32_t minorSectors)
600  {
601      vector<Math::Vec3> vertices;
602      vector<Math::Vec3> normals;
603      vector<Math::Vec2> uvs;
604      vector<uint32_t> indices;
605      GenerateTorusGeometry(majorRadius, minorRadius, majorSectors, minorSectors, { vertices, normals, uvs, indices });
606  
607      vector<Math::Vec4> tangents(vertices.size());
608      CalculateTangents(indices, vertices, normals, uvs, tangents);
609  
610      IMeshBuilder::Submesh submesh;
611      submesh.material = material;
612      submesh.vertexCount = static_cast<uint32_t>(vertices.size());
613      submesh.indexCount = static_cast<uint32_t>(indices.size());
614      submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
615      submesh.tangents = true;
616  
617      auto builder = InitializeBuilder(submesh);
618  
619      auto positionData = FillData(vertices);
620      auto normalData = FillData(normals);
621      auto uvData = FillData(uvs);
622      auto tangentData = FillData(tangents);
623      IMeshBuilder::DataBuffer dummy {};
624      builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
625  
626      builder->CalculateAABB(0, positionData);
627  
628      auto indexData = FillData(indices);
629      builder->SetIndexData(0, indexData);
630  
631      return CreateMesh(ecs, *builder, name);
632  }
633  
GenerateCubeMesh(const IEcs & ecs,const string_view name,Entity material,float width,float height,float depth)634  Entity MeshUtil::GenerateCubeMesh(
635      const IEcs& ecs, const string_view name, Entity material, float width, float height, float depth)
636  {
637      vector<Math::Vec3> positions;
638      vector<Math::Vec3> normals;
639      vector<Math::Vec2> uvs;
640      vector<uint16_t> indices;
641      GenerateCubeGeometry(width, height, depth, { positions, normals, uvs, indices });
642  
643      vector<Math::Vec4> tangents(positions.size());
644      CalculateTangents(indices, positions, normals, uvs, tangents);
645  
646      IMeshBuilder::Submesh submesh;
647      submesh.material = material;
648      submesh.vertexCount = static_cast<uint32_t>(countof(CUBE_INDICES));
649      submesh.indexCount = static_cast<uint32_t>(countof(CUBE_INDICES));
650      submesh.indexType = CORE_INDEX_TYPE_UINT16;
651      submesh.tangents = true;
652  
653      auto builder = InitializeBuilder(submesh);
654  
655      auto positionData = FillData(positions);
656      auto normalData = FillData(normals);
657      auto uvData = FillData(uvs);
658      auto tangentData = FillData(tangents);
659      IMeshBuilder::DataBuffer dummy {};
660      builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
661  
662      builder->CalculateAABB(0, positionData);
663  
664      auto indexData = FillData(indices);
665      builder->SetIndexData(0, indexData);
666  
667      return CreateMesh(ecs, *builder, name);
668  }
669  
GenerateEntity(const IEcs & ecs,const string_view name,Entity meshHandle)670  Entity MeshUtil::GenerateEntity(const IEcs& ecs, const string_view name, Entity meshHandle)
671  {
672      INodeSystem* nodesystem = GetSystem<INodeSystem>(ecs);
673      CORE_ASSERT(nodesystem);
674  
675      // Create node to scene.
676      ISceneNode* node = nodesystem->CreateNode();
677      if (!node) {
678          return Entity {};
679      }
680  
681      node->SetName(name);
682  
683      // Add render mesh component.
684      IRenderMeshComponentManager* renderMeshManager = GetManager<IRenderMeshComponentManager>(ecs);
685      CORE_ASSERT(renderMeshManager);
686  
687      RenderMeshComponent component = CreateComponent(*renderMeshManager, node->GetEntity());
688      component.mesh = meshHandle;
689      renderMeshManager->Set(node->GetEntity(), component);
690  
691      return node->GetEntity();
692  }
693  
GenerateCube(const IEcs & ecs,const string_view name,Entity material,float width,float height,float depth)694  Entity MeshUtil::GenerateCube(
695      const IEcs& ecs, const string_view name, Entity material, float width, float height, float depth)
696  {
697      const Entity meshHandle = GenerateCubeMesh(ecs, name, material, width, height, depth);
698      return GenerateEntity(ecs, name, meshHandle);
699  }
700  
GeneratePlane(const IEcs & ecs,const string_view name,Entity material,float width,float depth)701  Entity MeshUtil::GeneratePlane(const IEcs& ecs, const string_view name, Entity material, float width, float depth)
702  {
703      const Entity meshHandle = GeneratePlaneMesh(ecs, name, material, width, depth);
704      return GenerateEntity(ecs, name, meshHandle);
705  }
706  
GenerateSphere(const IEcs & ecs,const string_view name,Entity material,float radius,uint32_t rings,uint32_t sectors)707  Entity MeshUtil::GenerateSphere(
708      const IEcs& ecs, const string_view name, Entity material, float radius, uint32_t rings, uint32_t sectors)
709  {
710      const Entity meshHandle = GenerateSphereMesh(ecs, name, material, radius, rings, sectors);
711      return GenerateEntity(ecs, name, meshHandle);
712  }
713  
GenerateCone(const IEcs & ecs,const string_view name,Entity material,float radius,float length,uint32_t sectors)714  Entity MeshUtil::GenerateCone(
715      const IEcs& ecs, const string_view name, Entity material, float radius, float length, uint32_t sectors)
716  {
717      const Entity meshHandle = GenerateConeMesh(ecs, name, material, radius, length, sectors);
718      return GenerateEntity(ecs, name, meshHandle);
719  }
720  
GenerateTorus(const IEcs & ecs,const string_view name,Entity material,float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors)721  Entity MeshUtil::GenerateTorus(const IEcs& ecs, const string_view name, Entity material, float majorRadius,
722      float minorRadius, uint32_t majorSectors, uint32_t minorSectors)
723  {
724      const Entity meshHandle =
725          GenerateTorusMesh(ecs, name, material, majorRadius, minorRadius, majorSectors, minorSectors);
726      return GenerateEntity(ecs, name, meshHandle);
727  }
728  
InitializeBuilder(const IMeshBuilder::Submesh & submesh) const729  IMeshBuilder::Ptr MeshUtil::InitializeBuilder(const IMeshBuilder::Submesh& submesh) const
730  {
731      IMeshBuilder::Ptr builder;
732      if (IClassRegister* classRegister = factory_.GetInterface<IClassRegister>(); classRegister) {
733          auto renderContext = GetInstance<IRenderContext>(*classRegister, UID_RENDER_CONTEXT);
734          IShaderManager& shaderManager = renderContext->GetDevice().GetShaderManager();
735          const VertexInputDeclarationView vertexInputDeclaration =
736              shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
737                  DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
738          builder = CreateInstance<IMeshBuilder>(*renderContext, UID_MESH_BUILDER);
739          builder->Initialize(vertexInputDeclaration, 1);
740  
741          builder->AddSubmesh(submesh);
742          builder->Allocate();
743      }
744  
745      return builder;
746  }
747  
CreateMesh(const IEcs & ecs,const IMeshBuilder & builder,const string_view name) const748  Entity MeshUtil::CreateMesh(const IEcs& ecs, const IMeshBuilder& builder, const string_view name) const
749  {
750      auto meshEntity = builder.CreateMesh(const_cast<IEcs&>(ecs));
751      if (!name.empty()) {
752          GetManager<IUriComponentManager>(ecs)->Set(meshEntity, { string(name) });
753          GetManager<INameComponentManager>(ecs)->Set(meshEntity, { string(name) });
754      }
755      return meshEntity;
756  }
757  
MeshUtil(IClassFactory & factory)758  MeshUtil::MeshUtil(IClassFactory& factory) : factory_(factory) {}
759  CORE3D_END_NAMESPACE()
760