Program Listing for File Icosphere.cpp¶
↰ Return to documentation for file (Source\Math\Src\Icosphere.cpp
)
#include "Math/Icosphere.h"
#include <array>
#include <vector>
#include <map>
#include "Math/Transform.h"
#include "Core/RawStorageFormat.h"
namespace Azura {
namespace Math {
namespace {
// Source Ref: https://schneide.blog/2016/07/15/generating-an-icosphere-in-c/
const float X = 0.525731112119133606f;
const float Z = 0.850650808352039932f;
const float N = 0.0f;
const RawStorageFormat VERTEX_FORMAT = RawStorageFormat::R32G32B32A32_FLOAT;
const RawStorageFormat NORMAL_FORMAT = RawStorageFormat::R32G32B32_FLOAT;
const RawStorageFormat INDEX_FORMAT = RawStorageFormat::R32_UINT;
using Lookup = std::map<std::pair<U32, U32>, U32>;
const std::array<Vector4f, 12> BASE_VERTICES =
{
Vector4f{-X, N, Z, 1.0f}, Vector4f{X, N, Z, 1.0f}, Vector4f{-X, N, -Z, 1.0f}, Vector4f{X, N, -Z, 1.0f},
Vector4f{N, Z, X, 1.0f}, Vector4f{N, Z, -X, 1.0f}, Vector4f{N, -Z, X, 1.0f}, Vector4f{N, -Z, -X, 1.0f},
Vector4f{Z, X, N, 1.0f}, Vector4f{-Z, X, N, 1.0f}, Vector4f{Z, -X, N, 1.0f}, Vector4f{-Z, -X, N, 1.0f}
};
const std::array<Vector3u, 20> BASE_TRIANGLES =
{
Vector3u{0, 4, 1}, Vector3u{0, 9, 4}, Vector3u{9, 5, 4}, Vector3u{4, 5, 8}, Vector3u{4, 8, 1},
Vector3u{8, 10, 1}, Vector3u{8, 3, 10}, Vector3u{5, 3, 8}, Vector3u{5, 2, 3}, Vector3u{2, 7, 3},
Vector3u{7, 10, 3}, Vector3u{7, 6, 10}, Vector3u{7, 11, 6}, Vector3u{11, 0, 6}, Vector3u{0, 1, 6},
Vector3u{6, 1, 10}, Vector3u{9, 0, 11}, Vector3u{9, 11, 2}, Vector3u{9, 2, 5}, Vector3u{7, 2, 11}
};
U32 VertexForEdge(Lookup& lookup,
std::vector<Vector4f>& vertices,
U32 first,
U32 second) {
Lookup::key_type key(first, second);
if (key.first > key.second) {
std::swap(key.first, key.second);
}
const auto inserted = lookup.insert({key, U32(vertices.size())});
if (inserted.second) {
auto& edge0 = vertices[first];
auto& edge1 = vertices[second];
const Vector3f data = Transform::Downgrade(edge0 + edge1);
const auto point = mathfu::NormalizedHelper(data);
vertices.emplace_back(point, 1.0f);
}
return inserted.first->second;
}
std::vector<Vector3u> SubDivide(std::vector<Vector4f>& vertices,
std::vector<Vector3u> triangles) {
Lookup lookup;
std::vector<Vector3u> result;
result.reserve(triangles.size() * 4);
for (auto&& each : triangles) {
Vector3u mid;
for (int edge = 0; edge < 3; ++edge) {
mid[edge] = VertexForEdge(lookup, vertices, each[edge], each[(edge + 1) % 3]);
}
result.emplace_back(each[0], mid[0], mid[2]);
result.emplace_back(each[1], mid[1], mid[0]);
result.emplace_back(each[2], mid[2], mid[1]);
result.emplace_back(mid[0], mid[1], mid[2]);
}
return result;
}
} // namespace
IcoSphere::IcoSphere(U32 subDivisions)
: m_vertices(BASE_VERTICES.begin(), BASE_VERTICES.end()),
m_triangles(BASE_TRIANGLES.begin(), BASE_TRIANGLES.end()) {
m_vertices.reserve(10 * U32(std::pow(4, subDivisions)));
m_normals.reserve(10 * U32(std::pow(4, subDivisions)));
m_triangles.reserve(10 * U32(std::pow(4, subDivisions)));
for (U32 idx = 0; idx < subDivisions; ++idx) {
m_triangles = SubDivide(m_vertices, m_triangles);
}
for (const auto& vertex: m_vertices)
{
m_normals.push_back(Transform::Downgrade(vertex).Normalized());
}
}
U32 IcoSphere::VertexDataSize() const {
return U32(m_vertices.size() * GetFormatSize(VERTEX_FORMAT));
}
U32 IcoSphere::IndexDataSize() const {
return U32(m_triangles.size() * GetFormatSize(INDEX_FORMAT) * 3);
}
U32 IcoSphere::NormalDataSize() const {
return U32(m_normals.size() * GetFormatSize(NORMAL_FORMAT));
}
const U8* IcoSphere::VertexData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_vertices.data());
}
const U8* IcoSphere::IndexData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_triangles.data());
}
const U8* IcoSphere::NormalData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_normals.data());
}
RawStorageFormat IcoSphere::GetVertexFormat() const {
return VERTEX_FORMAT;
}
RawStorageFormat IcoSphere::GetIndexFormat() const {
return INDEX_FORMAT;
}
RawStorageFormat IcoSphere::GetNormalFormat() const {
return NORMAL_FORMAT;
}
U32 IcoSphere::UVDataSize() const {
// TODO(vasumahesh1): Not Implemented
return 0;
}
const U8* IcoSphere::UVData() const {
// TODO(vasumahesh1): Not Implemented
return nullptr;
}
RawStorageFormat IcoSphere::GetUVFormat() const {
// TODO(vasumahesh1): Not Implemented
return RawStorageFormat::UNKNOWN;
}
U32 IcoSphere::GetVertexCount() const {
return U32(m_vertices.size());
}
U32 IcoSphere::GetIndexCount() const {
return U32(m_triangles.size() * 3);
}
U32 IcoSphere::TotalDataSize() const {
return VertexDataSize() + IndexDataSize() + NormalDataSize();
}
} // namespace Math
} // namespace Azura