feat: multiple index buffers per mesh support

This commit is contained in:
MihailRis 2025-07-24 21:40:00 +03:00
parent 6debc92ae5
commit 4a6ccf4847
7 changed files with 81 additions and 43 deletions

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <vector>
#include "MeshData.hpp" #include "MeshData.hpp"
@ -8,25 +10,32 @@ struct MeshStats {
static int drawCalls; static int drawCalls;
}; };
struct IndexBufferData {
const uint32_t* indices;
size_t indicesCount;
};
template <typename VertexStructure> template <typename VertexStructure>
class Mesh { class Mesh {
struct IndexBuffer {
unsigned int ibo;
size_t indexCount;
};
unsigned int vao; unsigned int vao;
unsigned int vbo; unsigned int vbo;
unsigned int ibo; std::vector<IndexBuffer> ibos;
size_t vertexCount; size_t vertexCount;
size_t indexCount;
public: public:
explicit Mesh(const MeshData<VertexStructure>& data); explicit Mesh(const MeshData<VertexStructure>& data);
Mesh( Mesh(
const VertexStructure* vertexBuffer, const VertexStructure* vertexBuffer,
size_t vertices, size_t vertices,
const uint32_t* indexBuffer, std::vector<IndexBufferData> indices
size_t indices
); );
Mesh(const VertexStructure* vertexBuffer, size_t vertices) Mesh(const VertexStructure* vertexBuffer, size_t vertices)
: Mesh<VertexStructure>(vertexBuffer, vertices, nullptr, 0) {}; : Mesh<VertexStructure>(vertexBuffer, vertices, {}) {};
~Mesh(); ~Mesh();
@ -34,18 +43,21 @@ public:
/// attributes /// attributes
/// @param vertexBuffer vertex data buffer /// @param vertexBuffer vertex data buffer
/// @param vertexCount number of vertices in new buffer /// @param vertexCount number of vertices in new buffer
/// @param indexBuffer indices buffer /// @param indices indices buffer
/// @param indexCount number of values in indices buffer
void reload( void reload(
const VertexStructure* vertexBuffer, const VertexStructure* vertexBuffer,
size_t vertexCount, size_t vertexCount,
const uint32_t* indexBuffer = nullptr, const std::vector<IndexBufferData>& indices
size_t indexCount = 0
); );
void reload(const VertexStructure* vertexBuffer, size_t vertexCount) {
static const std::vector<IndexBufferData> indices {};
reload(vertexBuffer, vertexCount, indices);
}
/// @brief Draw mesh with specified primitives type /// @brief Draw mesh with specified primitives type
/// @param primitive primitives type /// @param iboIndex index of used element buffer
void draw(unsigned int primitive) const; void draw(unsigned int primitive, int iboIndex = 0) const;
/// @brief Draw mesh as triangles /// @brief Draw mesh as triangles
void draw() const; void draw() const;

View File

@ -11,13 +11,21 @@ inline constexpr size_t calc_size(const VertexAttribute attrs[]) {
return vertexSize; return vertexSize;
} }
template <typename VertexStructure>
inline std::vector<IndexBufferData> convert_to_ibd(const MeshData<VertexStructure>& data) {
std::vector<IndexBufferData> indices;
for (const auto& buffer : data.indices) {
indices.push_back(IndexBufferData {buffer.data(), buffer.size()});
}
return indices;
}
template <typename VertexStructure> template <typename VertexStructure>
Mesh<VertexStructure>::Mesh(const MeshData<VertexStructure>& data) Mesh<VertexStructure>::Mesh(const MeshData<VertexStructure>& data)
: Mesh( : Mesh(
data.vertices.data(), data.vertices.data(),
data.vertices.size(), data.vertices.size(),
data.indices.data(), convert_to_ibd<VertexStructure>(data)
data.indices.size()
) { ) {
} }
@ -25,10 +33,9 @@ template <typename VertexStructure>
Mesh<VertexStructure>::Mesh( Mesh<VertexStructure>::Mesh(
const VertexStructure* vertexBuffer, const VertexStructure* vertexBuffer,
size_t vertices, size_t vertices,
const uint32_t* indexBuffer, std::vector<IndexBufferData> indices
size_t indices
) )
: vao(0), vbo(0), ibo(0), vertexCount(0), indexCount(0) { : vao(0), vbo(0), ibos(), vertexCount(0) {
static_assert( static_assert(
calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure) calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure)
); );
@ -39,8 +46,9 @@ Mesh<VertexStructure>::Mesh(
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo); glGenBuffers(1, &vbo);
reload(vertexBuffer, vertices, indexBuffer, indices); reload(vertexBuffer, vertices, std::move(indices));
glBindVertexArray(vao);
// attributes // attributes
int offset = 0; int offset = 0;
for (int i = 0; attrs[i].count; i++) { for (int i = 0; attrs[i].count; i++) {
@ -65,8 +73,8 @@ Mesh<VertexStructure>::~Mesh() {
MeshStats::meshesCount--; MeshStats::meshesCount--;
glDeleteVertexArrays(1, &vao); glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &vbo);
if (ibo != 0) { for (int i = ibos.size() - 1; i >= 0; i--) {
glDeleteBuffers(1, &ibo); glDeleteBuffers(1, &ibos[i].ibo);
} }
} }
@ -74,11 +82,9 @@ template <typename VertexStructure>
void Mesh<VertexStructure>::reload( void Mesh<VertexStructure>::reload(
const VertexStructure* vertexBuffer, const VertexStructure* vertexBuffer,
size_t vertexCount, size_t vertexCount,
const uint32_t* indexBuffer, const std::vector<IndexBufferData>& indices
size_t indexCount
) { ) {
this->vertexCount = vertexCount; this->vertexCount = vertexCount;
this->indexCount = indexCount;
glBindVertexArray(vao); glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
if (vertexBuffer != nullptr && vertexCount != 0) { if (vertexBuffer != nullptr && vertexCount != 0) {
@ -92,30 +98,47 @@ void Mesh<VertexStructure>::reload(
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
} }
if (indexBuffer != nullptr && indexCount != 0) { for (int i = indices.size(); i < ibos.size(); i++) {
if (ibo == 0) glGenBuffers(1, &ibo); glDeleteBuffers(1, &ibos[i].ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); }
ibos.clear();
for (int i = 0; i < indices.size(); i++) {
const auto& indexBuffer = indices[i];
ibos.push_back(IndexBuffer {0, 0});
glGenBuffers(1, &ibos[i].ibo);
ibos[i].indexCount = indexBuffer.indicesCount;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[i].ibo);
glBufferData( glBufferData(
GL_ELEMENT_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
sizeof(uint32_t) * indexCount, sizeof(uint32_t) * indexBuffer.indicesCount,
indexBuffer, indexBuffer.indices,
GL_STATIC_DRAW GL_STATIC_DRAW
); );
} else if (ibo != 0) {
glDeleteBuffers(1, &ibo);
} }
glBindVertexArray(0);
} }
template <typename VertexStructure> template <typename VertexStructure>
void Mesh<VertexStructure>::draw(unsigned int primitive) const { void Mesh<VertexStructure>::draw(unsigned int primitive, int iboIndex) const {
MeshStats::drawCalls++; MeshStats::drawCalls++;
glBindVertexArray(vao);
if (ibo != 0) { if (!ibos.empty()) {
glDrawElements(primitive, indexCount, GL_UNSIGNED_INT, nullptr); if (iboIndex < ibos.size()) {
} else { glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[
std::min(static_cast<size_t>(iboIndex), ibos.size())
].ibo);
glDrawElements(
primitive, ibos.at(0).indexCount, GL_UNSIGNED_INT, nullptr
);
glBindVertexArray(0);
}
} else if (vertexCount > 0) {
glBindVertexArray(vao);
glDrawArrays(primitive, 0, vertexCount); glDrawArrays(primitive, 0, vertexCount);
glBindVertexArray(0);
} }
glBindVertexArray(0);
} }
template <typename VertexStructure> template <typename VertexStructure>

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <vector>
#include <stdexcept> #include <stdexcept>
#include "typedefs.hpp" #include "typedefs.hpp"
@ -40,7 +41,7 @@ struct VertexAttribute {
template<typename VertexStructure> template<typename VertexStructure>
struct MeshData { struct MeshData {
util::Buffer<VertexStructure> vertices; util::Buffer<VertexStructure> vertices;
util::Buffer<uint32_t> indices; std::vector<util::Buffer<uint32_t>> indices;
util::Buffer<VertexAttribute> attrs; util::Buffer<VertexAttribute> attrs;
MeshData() = default; MeshData() = default;
@ -50,7 +51,7 @@ struct MeshData {
/// @param attrs vertex attribute sizes (must be null-terminated) /// @param attrs vertex attribute sizes (must be null-terminated)
MeshData( MeshData(
util::Buffer<VertexStructure> vertices, util::Buffer<VertexStructure> vertices,
util::Buffer<uint32_t> indices, std::vector<util::Buffer<uint32_t>> indices,
util::Buffer<VertexAttribute> attrs util::Buffer<VertexAttribute> attrs
) : vertices(std::move(vertices)), ) : vertices(std::move(vertices)),
indices(std::move(indices)), indices(std::move(indices)),

View File

@ -706,6 +706,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
vertexCount = 0; vertexCount = 0;
vertexOffset = 0; vertexOffset = 0;
indexCount = 0; indexCount = 0;
denseRender = settings.graphics.denseRender.get();
render(voxels, beginEnds); render(voxels, beginEnds);
} }
@ -714,7 +715,7 @@ ChunkMeshData BlocksRenderer::createMesh() {
return ChunkMeshData{ return ChunkMeshData{
MeshData( MeshData(
util::Buffer(vertexBuffer.get(), vertexCount), util::Buffer(vertexBuffer.get(), vertexCount),
util::Buffer(indexBuffer.get(), indexCount), std::vector<util::Buffer<uint32_t>> {util::Buffer(indexBuffer.get(), indexCount)},
util::Buffer( util::Buffer(
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
) )
@ -727,7 +728,8 @@ ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) {
build(chunk, chunks); build(chunk, chunks);
return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>( return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>(
vertexBuffer.get(), vertexCount, indexBuffer.get(), indexCount vertexBuffer.get(), vertexCount,
std::vector<IndexBufferData> {IndexBufferData {indexBuffer.get(), indexCount}}
), std::move(sortingMesh)}; ), std::move(sortingMesh)};
} }

View File

@ -33,6 +33,7 @@ class BlocksRenderer {
int voxelBufferPadding = 2; int voxelBufferPadding = 2;
bool overflow = false; bool overflow = false;
bool cancelled = false; bool cancelled = false;
bool denseRender = false;
const Chunk* chunk = nullptr; const Chunk* chunk = nullptr;
std::unique_ptr<VoxelsVolume> voxelsBuffer; std::unique_ptr<VoxelsVolume> voxelsBuffer;
@ -137,7 +138,7 @@ class BlocksRenderer {
} }
if ((variant.culling == CullingMode::DISABLED || if ((variant.culling == CullingMode::DISABLED ||
(variant.culling == CullingMode::OPTIONAL && (variant.culling == CullingMode::OPTIONAL &&
settings.graphics.denseRender.get())) && denseRender)) &&
vox.id == def.rt.id) { vox.id == def.rt.id) {
return true; return true;
} }

View File

@ -89,8 +89,7 @@ ChunksRenderer::ChunksRenderer(
logger.info() << "created " << threadPool.getWorkersCount() << " workers"; logger.info() << "created " << threadPool.getWorkersCount() << " workers";
} }
ChunksRenderer::~ChunksRenderer() { ChunksRenderer::~ChunksRenderer() = default;
}
const Mesh<ChunkVertex>* ChunksRenderer::render( const Mesh<ChunkVertex>* ChunksRenderer::render(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important

View File

@ -47,7 +47,7 @@ struct ChunkMeshData {
}; };
struct ChunkMesh { struct ChunkMesh {
std::unique_ptr<Mesh<ChunkVertex> > mesh; std::unique_ptr<Mesh<ChunkVertex>> mesh;
SortingMeshData sortingMeshData; SortingMeshData sortingMeshData;
std::unique_ptr<Mesh<ChunkVertex> > sortedMesh = nullptr; std::unique_ptr<Mesh<ChunkVertex> > sortedMesh = nullptr;
}; };