diff --git a/src/Mesh.h b/src/Mesh.h new file mode 100644 index 0000000..fc21258 --- /dev/null +++ b/src/Mesh.h @@ -0,0 +1,84 @@ +#pragma once + +#include + +#include +#include + + +template +class GenericMesh { +public: + using Scalar = TScalar; + using Index = TIndex; + using Vector = Eigen::Matrix; + +public: + GenericMesh() = default; + GenericMesh(const GenericMesh&) = delete; + GenericMesh(GenericMesh&&) = default; + ~GenericMesh() = default; + + GenericMesh& operator=(const GenericMesh&) = delete; + GenericMesh& operator=(GenericMesh&&) = default; + + inline size_t vertexCount() const { + return m_positions.size(); + } + inline size_t indexCount() const { + return m_indices.size(); + } + + inline void resizeVertex(Index vertexCount) { + m_positions.resize(vertexCount); + } + inline void resizeIndices(Index indexCount) { + m_indices.resize(indexCount); + } + + inline const Vector& position(Index vertexIndex) const { + assert(vertexIndex < m_positions.size()); + return m_positions[vertexIndex]; + } + inline Vector& position(Index vertexIndex) { + assert(vertexIndex < m_positions.size()); + return m_positions[vertexIndex]; + } + + inline Index index(Index indexIndex) const { + assert(indexIndex < m_indices.size()); + return m_indices[indexIndex]; + } + inline Index& index(Index indexIndex) { + assert(indexIndex < m_indices.size()); + return m_indices[indexIndex]; + } + + inline const Vector* positionData() const { + return m_positions.data(); + } + inline Vector* positionData() { + return m_positions.data(); + } + + inline const Index* indexData() const { + return m_indices.data(); + } + inline Index* indexData() { + return m_indices.data(); + } + + inline const std::vector& positions() const { + return m_positions; + } + + inline const std::vector& indices() const { + return m_indices; + } + +private: + std::vector m_positions; + std::vector m_indices; +}; + +using Mesh = GenericMesh; diff --git a/src/Planet.cpp b/src/Planet.cpp index 87fb91a..6c29942 100644 --- a/src/Planet.cpp +++ b/src/Planet.cpp @@ -6,9 +6,25 @@ #include -Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1) { - return (Real(1) - factor) * v0 + factor * v1; -} +MeshView::MeshView( + Index vertex_count, + Byte* positions, Index position_stride, + Byte* normals, Index normal_stride, + Byte* colors, Index color_stride, + Index index_count, + Byte* indices, Index index_stride +) + : m_vertex_count(vertex_count) + , m_positions(positions) + , m_position_stride(position_stride) + , m_normals(normals) + , m_normal_stride(normal_stride) + , m_colors(colors) + , m_color_stride(color_stride) + , m_index_count(index_count) + , m_indices(indices) + , m_index_stride(index_stride) +{} Cell::Cell( @@ -18,13 +34,13 @@ Cell::Cell( const Vector3& corner11 ) : m_corners{ corner00, corner01, corner10, corner11 } - , m_heightFactor(heightFactor(m_corners)) + , m_height_factor(height_factor(m_corners)) , m_cells{ nullptr, nullptr, nullptr, nullptr } {} -Cell& Cell::cell(uint32_t cellIndex) { - assert(cellIndex < CellCount); - auto& cell = m_cells[cellIndex]; +Cell& Cell::cell(uint32_t cell_index) { + assert(cell_index < CellCount); + auto& cell = m_cells[cell_index]; if(!cell) { // TODO @@ -32,119 +48,159 @@ Cell& Cell::cell(uint32_t cellIndex) { return *cell; } -void Cell::writeMesh( - Vertex*& vertices, const Vertex* verticesEnd, - uint32_t*& indices, const uint32_t* indicesEnd, - uint32_t subdivCount -) const { - auto const sideEdgeCount = (1u << subdivCount); - auto const sideVertCount = sideEdgeCount + 1; +size_t Cell::vertex_count(uint32_t subdiv_count) { + auto const s2 = 1 << subdiv_count; + return s2 * s2 + 2 * s2 + 1; +} - auto const quadCount = sideEdgeCount * sideEdgeCount; - auto const triCount = 2 * quadCount; - auto const vertCount = sideVertCount * sideVertCount; +size_t Cell::triangle_count(uint32_t subdiv_count) { + auto const s2 = 1 << subdiv_count; + return 2 * s2 * s2; +} - assert(vertices + vertCount <= verticesEnd); - assert(indices + (3 * triCount) <= indicesEnd); +void Cell::build_mesh(MeshView& mesh, uint32_t subdiv_count, Index index_offset) const { + auto const side_edge_count = (1u << subdiv_count); + auto const side_vert_count = side_edge_count + 1; - auto const index = [sideVertCount](uint32_t x, uint32_t y) -> uint32_t { - return x + y * sideVertCount; - }; - auto const vertex = [vertices, &index](uint32_t x, uint32_t y) -> Vertex& { - return vertices[index(x, y)]; - }; + auto const quad_count = side_edge_count * side_edge_count; + auto const tri_count = 2 * quad_count; + auto const vert_count = side_vert_count * side_vert_count; - Vector3 c00(0.0f, 0.0f, 1.0f); - Vector3 c01(1.0f, 0.0f, 1.0f); - Vector3 c10(0.0f, 1.0f, 1.0f); - Vector3 c11(1.0f, 1.0f, 1.0f); + assert(mesh.vertex_count() == vert_count); + assert(mesh.index_count() == 3 * tri_count); - auto const color = [&c00, &c01, &c10, &c11, sideEdgeCount](uint32_t x, uint32_t y) -> Vector3 { - const auto c0 = lerp(Real(x) / Real(sideEdgeCount), c00, c01); - const auto c1 = lerp(Real(x) / Real(sideEdgeCount), c10, c11); - return lerp(Real(y) / Real(sideEdgeCount), c0, c1); + auto const index = [side_vert_count](uint32_t x, uint32_t y) -> uint32_t { + return x + y * side_vert_count; }; - - auto const setVertex = [&vertex, &color](uint32_t x, uint32_t y, const Vector3& pos) { - vertex(x, y) = Vertex { - pos, - color(x, y) - }; + auto const vertex = [&mesh, &index](uint32_t x, uint32_t y) -> Vector3& { + return mesh.position(index(x, y)); }; - setVertex( 0, 0, m_corners[0]); - setVertex(sideEdgeCount, 0, m_corners[1]); - setVertex( 0, sideEdgeCount, m_corners[2]); - setVertex(sideEdgeCount, sideEdgeCount, m_corners[3]); + vertex( 0, 0) = m_corners[0]; + vertex(side_edge_count, 0) = m_corners[1]; + vertex( 0, side_edge_count) = m_corners[2]; + vertex(side_edge_count, side_edge_count) = m_corners[3]; struct QuadCell { uint32_t x0, x1, y0, y1; }; std::vector stack; - stack.reserve(quadCount / 4); - if(subdivCount > 0) { + stack.reserve(quad_count / 4); + if(subdiv_count > 0) { stack.emplace_back(QuadCell { - 0, sideEdgeCount, - 0, sideEdgeCount, + 0, side_edge_count, + 0, side_edge_count, }); } while(!stack.empty()) { - const auto quadCell = stack.back(); + const auto quad_cell = stack.back(); stack.pop_back(); - auto const mx = (quadCell.x0 + quadCell.x1) / 2; - auto const my = (quadCell.y0 + quadCell.y1) / 2; - - auto const& v00 = vertex(quadCell.x0, quadCell.y0).position; - auto const& v01 = vertex(quadCell.x1, quadCell.y0).position; - auto const& v10 = vertex(quadCell.x0, quadCell.y1).position; - auto const& v11 = vertex(quadCell.x1, quadCell.y1).position; - - setVertex( mx, quadCell.y0, - (v00 + v01).normalized() - ); - setVertex(quadCell.x0, my, - (v00 + v10).normalized() - ); - setVertex(mx, my, - (v00 + v01 + v10 + v11).normalized() - ); - setVertex(quadCell.x1, my, - (v01 + v11).normalized() - ); - setVertex( mx, quadCell.y1, - (v10 + v11).normalized() - ); - - if(quadCell.x0 + 1 < mx) { - stack.emplace_back(QuadCell { mx, quadCell.x1, my, quadCell.y1 }); - stack.emplace_back(QuadCell { quadCell.x0, mx, my, quadCell.y1 }); - stack.emplace_back(QuadCell { mx, quadCell.x1, quadCell.y0, my }); - stack.emplace_back(QuadCell { quadCell.x0, mx, quadCell.y0, my }); + auto const mx = (quad_cell.x0 + quad_cell.x1) / 2; + auto const my = (quad_cell.y0 + quad_cell.y1) / 2; + + auto const& v00 = vertex(quad_cell.x0, quad_cell.y0); + auto const& v01 = vertex(quad_cell.x1, quad_cell.y0); + auto const& v10 = vertex(quad_cell.x0, quad_cell.y1); + auto const& v11 = vertex(quad_cell.x1, quad_cell.y1); + + vertex( mx, quad_cell.y0) = + (v00 + v01).normalized(); + vertex(quad_cell.x0, my) = + (v00 + v10).normalized(); + vertex(mx, my) = + (v00 + v01 + v10 + v11).normalized(); + vertex(quad_cell.x1, my) = + (v01 + v11).normalized(); + vertex( mx, quad_cell.y1) = + (v10 + v11).normalized(); + + if(quad_cell.x0 + 1 < mx) { + stack.emplace_back(QuadCell { mx, quad_cell.x1, my, quad_cell.y1 }); + stack.emplace_back(QuadCell { quad_cell.x0, mx, my, quad_cell.y1 }); + stack.emplace_back(QuadCell { mx, quad_cell.x1, quad_cell.y0, my }); + stack.emplace_back(QuadCell { quad_cell.x0, mx, quad_cell.y0, my }); } } - vertices += vertCount; - for(uint32_t y = 0; y < sideEdgeCount; y += 1) { - for(uint32_t x = 0; x < sideEdgeCount; x += 1) { - const auto i00 = index(x, y); + auto indexIndex = 0; + for(uint32_t y = 0; y < side_edge_count; y += 1) { + for(uint32_t x = 0; x < side_edge_count; x += 1) { + const auto i00 = index_offset + index(x, y); const auto i01 = i00 + 1; - const auto i10 = i00 + sideVertCount; + const auto i10 = i00 + side_vert_count; const auto i11 = i10 + 1; - *(indices++) = i00; - *(indices++) = i01; - *(indices++) = i10; + mesh.index(indexIndex++) = i00; + mesh.index(indexIndex++) = i01; + mesh.index(indexIndex++) = i10; - *(indices++) = i10; - *(indices++) = i01; - *(indices++) = i11; + mesh.index(indexIndex++) = i10; + mesh.index(indexIndex++) = i01; + mesh.index(indexIndex++) = i11; } } } -Real Cell::heightFactor(Vector3 corners[CornerCount]) { +Real Cell::height_factor(Vector3 corners[CornerCount]) { Vector3 c = (corners[0] + corners[1] + corners[2] + corners[3]).normalized(); return Real(1) / corners[0].dot(c); } + + + +Planet::Planet() + : m_cells { + { + Vector3(-1.0, -1.0, -1.0).normalized(), + Vector3( 1.0, -1.0, -1.0).normalized(), + Vector3(-1.0, 1.0, -1.0).normalized(), + Vector3( 1.0, 1.0, -1.0).normalized(), + }, + { + Vector3( 1.0, -1.0, -1.0).normalized(), + Vector3( 1.0, -1.0, 1.0).normalized(), + Vector3( 1.0, 1.0, -1.0).normalized(), + Vector3( 1.0, 1.0, 1.0).normalized(), + }, + { + Vector3( 1.0, -1.0, 1.0).normalized(), + Vector3(-1.0, -1.0, 1.0).normalized(), + Vector3( 1.0, 1.0, 1.0).normalized(), + Vector3(-1.0, 1.0, 1.0).normalized(), + }, + { + Vector3(-1.0, -1.0, 1.0).normalized(), + Vector3(-1.0, -1.0, -1.0).normalized(), + Vector3(-1.0, 1.0, 1.0).normalized(), + Vector3(-1.0, 1.0, -1.0).normalized(), + }, + { + Vector3(-1.0, -1.0, 1.0).normalized(), + Vector3( 1.0, -1.0, 1.0).normalized(), + Vector3(-1.0, -1.0, -1.0).normalized(), + Vector3( 1.0, -1.0, -1.0).normalized(), + }, + { + Vector3(-1.0, 1.0, -1.0).normalized(), + Vector3( 1.0, 1.0, -1.0).normalized(), + Vector3(-1.0, 1.0, 1.0).normalized(), + Vector3( 1.0, 1.0, 1.0).normalized(), + }, + } +{} + +void Planet::build_mesh(MeshView& mesh, uint32_t subdiv_count, Index index_offset) const { + auto const vertex_count = Cell::vertex_count(subdiv_count); + auto const index_count = 3 * Cell::triangle_count(subdiv_count); + + for(Index cell_index = 0; cell_index < CellCount; cell_index += 1) { + auto sub_mesh = mesh.view( + vertex_count, cell_index * vertex_count, + index_count, cell_index * index_count + ); + cell(cell_index).build_mesh(sub_mesh, subdiv_count, + index_offset + cell_index * vertex_count); + } +} diff --git a/src/Planet.h b/src/Planet.h index 8dabb3f..2fe9de3 100644 --- a/src/Planet.h +++ b/src/Planet.h @@ -1,13 +1,11 @@ #pragma once -#include +#include #include +#include -using Real = float; -using Vector3 = Eigen::Matrix; - class Cell; using CellUP = std::unique_ptr; @@ -18,7 +16,85 @@ struct Vertex { }; -Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1); +class MeshView { +public: + MeshView( + Index vertex_count, + Byte* positions, Index position_stride, + Byte* normals, Index normal_stride, + Byte* colors, Index color_stride, + Index index_count, + Byte* indices, Index index_stride + ); + ~MeshView() = default; + + inline Index vertex_count() const { + return m_vertex_count; + } + inline Index index_count() const { + return m_index_count; + } + + MeshView view( + Index vertex_count, Index vertex_index, + Index index_count, Index index_index + ) { + assert(vertex_index + vertex_count <= m_vertex_count); + assert(index_index + index_count <= m_index_count); + return MeshView( + vertex_count, + m_positions + (vertex_index * m_position_stride), + m_position_stride, + m_normals + (vertex_index * m_normal_stride), + m_normal_stride, + m_colors + (vertex_index * m_color_stride), + m_color_stride, + index_count, + m_indices + (index_index * m_index_stride), + m_index_stride + ); + } + + inline Vector3& position(Index vertex_index) { + assert(vertex_index < m_vertex_count); + return *reinterpret_cast( + m_positions + (vertex_index * m_position_stride) + ); + } + + inline Vector3& normal(Index vertex_index) { + assert(vertex_index < m_vertex_count); + return *reinterpret_cast( + m_normals + (vertex_index * m_normal_stride) + ); + } + + inline Vector3& color(Index vertex_index) { + assert(vertex_index < m_vertex_count); + return *reinterpret_cast( + m_colors + (vertex_index * m_color_stride) + ); + } + + inline Index& index(Index index_index) { + assert(index_index < m_index_count); + return *reinterpret_cast( + m_indices + (index_index * m_index_stride) + ); + } + +private: + Index m_vertex_count; + Byte* m_positions; + Index m_position_stride; + Byte* m_normals; + Index m_normal_stride; + Byte* m_colors; + Index m_color_stride; + Index m_index_count; + Byte* m_indices; + Index m_index_stride; +}; class Cell { @@ -40,20 +116,19 @@ public: Cell& operator=(const Cell&) = delete; Cell& operator=(Cell&&) = default; - Cell& cell(uint32_t cellIndex); + Cell& cell(uint32_t cell_index); + + static size_t vertex_count(uint32_t subdiv_count); + static size_t triangle_count(uint32_t subdiv_count); - void writeMesh( - Vertex*& vertices, const Vertex* verticesEnd, - uint32_t*& indices, const uint32_t* indicesEnd, - uint32_t subdivCount = 4 - ) const; + void build_mesh(MeshView& mesh, uint32_t subdiv_count=4, Index index_offset=0) const; private: - static Real heightFactor(Vector3 corners[CornerCount]); + static Real height_factor(Vector3 corners[CornerCount]); private: Vector3 m_corners[CornerCount]; - Real m_heightFactor; + Real m_height_factor; CellUP m_cells[CellCount]; }; @@ -71,8 +146,18 @@ public: Planet& operator=(const Planet&) = delete; Planet& operator=(Planet&&) = default; - Cell& cell(uint32_t cellIndex); + inline const Cell& cell(uint32_t cell_index) const { + assert(cell_index < CellCount); + return m_cells[cell_index]; + } + + inline Cell& cell(uint32_t cell_index) { + assert(cell_index < CellCount); + return m_cells[cell_index]; + } + + void build_mesh(MeshView& mesh, uint32_t subdiv_count=4, Index index_offset=0) const; private: - CellUP m_cells[CellCount]; + Cell m_cells[CellCount]; }; diff --git a/src/VulkanTutorial.cpp b/src/VulkanTutorial.cpp index bc3d8f9..efba0e7 100644 --- a/src/VulkanTutorial.cpp +++ b/src/VulkanTutorial.cpp @@ -86,48 +86,40 @@ VulkanTutorial::VulkanTutorial() { m_swapchain.register_destruction_callback( std::bind(&VulkanTutorial::destroy_swapchain_objects, this)); - auto const subdivCount = 2; - auto const sideEdgeCount = (1u << subdivCount); - auto const sideVertCount = sideEdgeCount + 1; - auto const quadCount = sideEdgeCount * sideEdgeCount; - auto const indexCount = 6 * quadCount; - auto const vertCount = sideVertCount * sideVertCount; - - vertices.assign(vertCount, Vertex{ - Vector3::Constant(std::numeric_limits::quiet_NaN()), - Vector3::Zero() - }); - indices.assign(indexCount, UINT32_MAX); + auto const subdiv_count = 4; - Cell cell( - Vector3(-1.0f, -1.0f, 1.0f).normalized(), - Vector3( 1.0f, -1.0f, 1.0f).normalized(), - Vector3(-1.0f, -1.0f, -1.0f).normalized(), - Vector3( 1.0f, -1.0f, -1.0f).normalized() - ); + vertices.resize(6 * Cell::vertex_count(subdiv_count)); + indices.resize(6 * 3 * Cell::triangle_count(subdiv_count)); - auto vertex = &*vertices.begin(); - const auto verticesEnd = &*vertices.end(); - auto index = &*indices.begin(); - const auto indicesEnd = &*indices.end(); - cell.writeMesh( - vertex, verticesEnd, - index, indicesEnd, - subdivCount + MeshView mesh( + vertices.size(), + reinterpret_cast(vertices.data()) + offsetof(Vertex, position), + sizeof(Vertex), + nullptr, + sizeof(Vertex), + reinterpret_cast(vertices.data()) + offsetof(Vertex, color), + sizeof(Vertex), + indices.size(), + reinterpret_cast(indices.data()), + sizeof(Index) ); - logger.info() << "Vertices:"; - for(auto v = &*vertices.begin(); v < vertex; v += 1) - logger.debug() << (v - &*vertices.begin()) << ": " - << v->position.transpose() << " - " - << v->color.transpose(); + Planet planet; + planet.build_mesh(mesh, subdiv_count); - logger.info() << "Indices:"; - for(auto i = &*indices.begin(); i < index; i += 6) - logger.debug() << (i - &*indices.begin()) << ": " - << i[0] << ", " << i[1] << ", " << i[2] << " - " - << i[3] << ", " << i[4] << ", " << i[5]; + for (size_t vertex_index = 0; vertex_index < vertices.size(); vertex_index += 1) { + mesh.color(vertex_index) = + mesh.position(vertex_index) / 2.0f + Vector3::Constant(0.5f); + } + // for(size_t vi = 0; vi < vertices.size(); vi += 1) + // logger.debug() << "v" << vi << ": " + // << vertices[vi].position.transpose(); + // for(size_t ii = 0; 3 * ii < indices.size(); ii += 1) + // logger.debug() << "i" << ii << ": " + // << indices[3 * ii + 0] << ", " + // << indices[3 * ii + 1] << ", " + // << indices[3 * ii + 2]; // abort(); } diff --git a/src/core.h b/src/core.h new file mode 100644 index 0000000..fb194f5 --- /dev/null +++ b/src/core.h @@ -0,0 +1,105 @@ +#pragma once + + +#include + +#include + + +using Byte = unsigned char; +using Index = uint32_t; +using Real = float; +using Vector3 = Eigen::Matrix; + + +template +auto lerp( + Scalar factor, + const Eigen::MatrixBase& m0, + const Eigen::MatrixBase& m1 +) -> std::enable_if_t< + Derived0::RowsAtCompileTime == Derived1::RowsAtCompileTime && + Derived0::ColsAtCompileTime == Derived1::ColsAtCompileTime, + Eigen::Matrix< + std::common_type_t< + Scalar, + typename Derived0::Scalar, + typename Derived1::Scalar + >, + Derived0::RowsAtCompileTime, + Derived0::ColsAtCompileTime + > +> { + return (Scalar(1) - factor) * m0 + factor * m1; +} + + +template +class ArrayView { +public: + ArrayView() = default; + ArrayView(const ArrayView&) = default; + ArrayView(ArrayView&&) = default; + ~ArrayView() = default; + + template + ArrayView(Index size, U* data, Index stride=sizeof(T)) + : m_data(reinterpret_cast(data)) + , m_size(size) + , m_stride(stride) + { + assert(m_data != nullptr || m_size == 0); + } + + explicit ArrayView(std::vector& vector) + : m_data(vector.data()) + , m_data(vector.size()) + {} + + ArrayView& operator=(const ArrayView&) = default; + ArrayView& operator=(ArrayView&&) = default; + + explicit operator bool() const { + return m_size != 0; + } + + Index size() const { + return m_size; + } + + Index stride() const { + return m_stride; + } + + const T* data() const { + return m_data; + } + + T* data() { + return m_data; + } + + const T& operator[](Index index) const { + assert(index < m_size); + return *reinterpret_cast(m_data + index * m_stride); + } + + T& operator[](Index index) { + return const_cast(const_cast(*this)[index]); + } + + ArrayView slice(Index start, Index count, Index step=1) { + assert(step > 0); + assert(start + count * step < m_size); + return ArrayView( + count, + m_data + start * m_stride, + m_stride * step + ); + } + +private: + Byte* m_data = nullptr; + Index m_size = 0; + Index m_stride = sizeof(T); +}; \ No newline at end of file