diff --git a/.gitignore b/.gitignore index 02ca8f1c..1dfd2a2a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ Debug/voxel_engine /world /worlds/**/* /settings.toml +/controls.json .vscode /.vs @@ -21,4 +22,4 @@ Debug/voxel_engine .cproject .project .git -/Default/ \ No newline at end of file +/Default/ diff --git a/src/graphics/BlocksRenderer.cpp b/src/graphics/BlocksRenderer.cpp index 92a1be3b..df2b0a42 100644 --- a/src/graphics/BlocksRenderer.cpp +++ b/src/graphics/BlocksRenderer.cpp @@ -17,60 +17,69 @@ using glm::vec4; #define VERTEX_SIZE 9 -BlocksRenderer::BlocksRenderer(size_t capacity) : offset(0), capacity(capacity) { - buffer = new float[capacity]; +BlocksRenderer::BlocksRenderer(size_t capacity) : vertexOffset(0), indexOffset(0), indexSize(0), capacity(capacity) { + vertexBuffer = new float[capacity]; + indexBuffer = new int[capacity]; voxelsBuffer = new VoxelsVolume(CHUNK_W + 2, CHUNK_H, CHUNK_D + 2); } - BlocksRenderer::~BlocksRenderer() { delete voxelsBuffer; - delete[] buffer; + delete[] vertexBuffer; + delete[] indexBuffer; } void BlocksRenderer::vertex(const vec3& coord, float u, float v, const vec4& light) { - buffer[offset++] = coord.x; - buffer[offset++] = coord.y; - buffer[offset++] = coord.z; + vertexBuffer[vertexOffset++] = coord.x; + vertexBuffer[vertexOffset++] = coord.y; + vertexBuffer[vertexOffset++] = coord.z; - buffer[offset++] = u; - buffer[offset++] = v; + vertexBuffer[vertexOffset++] = u; + vertexBuffer[vertexOffset++] = v; - buffer[offset++] = light.r; - buffer[offset++] = light.g; - buffer[offset++] = light.b; - buffer[offset++] = light.a; + vertexBuffer[vertexOffset++] = light.r; + vertexBuffer[vertexOffset++] = light.g; + vertexBuffer[vertexOffset++] = light.b; + vertexBuffer[vertexOffset++] = light.a; +} + +void BlocksRenderer::index(int a, int b, int c, int d, int e, int f) { + indexBuffer[indexSize++] = indexOffset + a; + indexBuffer[indexSize++] = indexOffset + b; + indexBuffer[indexSize++] = indexOffset + c; + indexBuffer[indexSize++] = indexOffset + d; + indexBuffer[indexSize++] = indexOffset + e; + indexBuffer[indexSize++] = indexOffset + f; + indexOffset += 4; } void BlocksRenderer::face(const vec3& coord, float w, float h, const vec3& axisX, const vec3& axisY, const UVRegion& region, - const vec4 (&lights)[4], + const vec4(&lights)[4], const vec4& tint) { - if (offset + VERTEX_SIZE * 6 > capacity) { + if (vertexOffset + VERTEX_SIZE * 6 > capacity) { overflow = true; return; } vertex(coord, region.u1, region.v1, lights[0] * tint); vertex(coord + axisX * w, region.u2, region.v1, lights[1] * tint); vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint); - - vertex(coord, region.u1, region.v1, lights[0] * tint); - vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint); vertex(coord + axisY * h, region.u1, region.v2, lights[3] * tint); + index(0, 1, 3, 0, 2, 3); } void BlocksRenderer::face(const vec3& coord, float w, float h, const vec3& axisX, const vec3& axisY, const UVRegion& region, - const vec4 (&lights)[4], + const vec4(&lights)[4], const vec4& tint, bool rotated) { - if (offset + VERTEX_SIZE * 6 > capacity) { + if (vertexOffset + VERTEX_SIZE * 6 > capacity) { overflow = true; return; } @@ -78,23 +87,19 @@ void BlocksRenderer::face(const vec3& coord, float w, float h, vertex(coord, region.u2, region.v1, lights[0] * tint); vertex(coord + axisX * w, region.u2, region.v2, lights[1] * tint); vertex(coord + axisX * w + axisY * h, region.u1, region.v2, lights[2] * tint); - - vertex(coord, region.u2, region.v1, lights[0] * tint); - vertex(coord + axisX * w + axisY * h, region.u1, region.v2, lights[2] * tint); vertex(coord + axisY * h, region.u1, region.v1, lights[3] * tint); + index(0, 1, 2, 0, 2, 3); } else { vertex(coord, region.u1, region.v1, lights[0] * tint); vertex(coord + axisX * w, region.u2, region.v1, lights[1] * tint); vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint); - - vertex(coord, region.u1, region.v1, lights[0] * tint); - vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint); vertex(coord + axisY * h, region.u1, region.v2, lights[3] * tint); + index(0, 1, 2, 0, 2, 3); } } -void BlocksRenderer::cube(const vec3& coord, const vec3& size, const UVRegion (&texfaces)[6]) { +void BlocksRenderer::cube(const vec3& coord, const vec3& size, const UVRegion(&texfaces)[6]) { vec4 lights[]{ vec4(),vec4(),vec4(),vec4() }; face(coord, size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[0], lights); @@ -111,7 +116,7 @@ inline vec4 do_tint(float value) { return vec4(value); } -void BlocksRenderer::blockCube(int x, int y, int z, const vec3& size, const UVRegion (&texfaces)[6], ubyte group) { +void BlocksRenderer::blockCube(int x, int y, int z, const vec3& size, const UVRegion(&texfaces)[6], ubyte group) { vec4 lights[]{ vec4(1.0f), vec4(1.0f), vec4(1.0f), vec4(1.0f) }; if (isOpen(x, y, z + 1, group)) { face(vec3(x, y, z), size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[5], lights, do_tint(0.9f)); @@ -138,8 +143,8 @@ void BlocksRenderer::blockCube(int x, int y, int z, const vec3& size, const UVRe void BlocksRenderer::blockXSprite(int x, int y, int z, const vec3& size, const UVRegion& texface1, const UVRegion& texface2, float spread) { vec4 lights[]{ - pickSoftLight(x, y+1, z, {1, 0, 0}, {0, 1, 0}), - pickSoftLight(x + 1, y+1, z, {1, 0, 0}, {0, 1, 0}), + pickSoftLight(x, y + 1, z, {1, 0, 0}, {0, 1, 0}), + pickSoftLight(x + 1, y + 1, z, {1, 0, 0}, {0, 1, 0}), pickSoftLight(x + 1, y + 1, z, {1, 0, 0}, {0, 1, 0}), pickSoftLight(x, y + 1, z, {1, 0, 0}, {0, 1, 0}) }; @@ -148,23 +153,23 @@ void BlocksRenderer::blockXSprite(int x, int y, int z, const vec3& size, const U float xs = ((float)(char)rand / 512) * spread; float zs = ((float)(char)(rand >> 8) / 512) * spread; - const float w = size.x/1.41f; - face(vec3(x + xs + (1.0 - w) * 0.5f, y, - z + zs - 1 + (1.0 - w) * 0.5f), w, size.y, - vec3(1.0f, 0, 1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.8f)); - face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y, - z + zs - (1.0 - w) * 0.5f), w, size.y, - vec3(-1.0f, 0, -1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.8f)); + const float w = size.x / 1.41f; + face(vec3(x + xs + (1.0 - w) * 0.5f, y, + z + zs - 1 + (1.0 - w) * 0.5f), w, size.y, + vec3(1.0f, 0, 1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.8f)); + face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y, + z + zs - (1.0 - w) * 0.5f), w, size.y, + vec3(-1.0f, 0, -1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.8f)); - face(vec3(x + xs + (1.0 - w) * 0.5f, y, - z + zs - (1.0 - w) * 0.5f), w, size.y, - vec3(1.0f, 0, -1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.8f)); - face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y, - z + zs + (1.0 - w) * 0.5f - 1), w, size.y, - vec3(-1.0f, 0, 1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.8f)); + face(vec3(x + xs + (1.0 - w) * 0.5f, y, + z + zs - (1.0 - w) * 0.5f), w, size.y, + vec3(1.0f, 0, -1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.8f)); + face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y, + z + zs + (1.0 - w) * 0.5f - 1), w, size.y, + vec3(-1.0f, 0, 1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.8f)); } -void BlocksRenderer::blockCubeShaded(int x, int y, int z, const vec3& size, const UVRegion (&texfaces_)[6], const Block* block, ubyte states) { +void BlocksRenderer::blockCubeShaded(int x, int y, int z, const vec3& size, const UVRegion(&texfaces_)[6], const Block* block, ubyte states) { ubyte group = block->drawGroup; UVRegion texfaces[6]; int rot = 0; @@ -296,7 +301,7 @@ inline UVRegion uvfor(const Block& def, uint face, int atlas_size) { const uint id = def.textureFaces[face]; float u = (id % atlas_size) * uvsize; float v = 1.0f - (id / atlas_size + 1) * uvsize; - return UVRegion(u+us, v+us, u + uvsize - us, v + uvsize - us); + return UVRegion(u + us, v + us, u + uvsize - us, v + uvsize - us); } void BlocksRenderer::render(const voxel* voxels, int atlas_size) { @@ -342,12 +347,13 @@ Mesh* BlocksRenderer::render(const Chunk* chunk, int atlas_size, const ChunksSto voxelsBuffer->setPosition(chunk->x * CHUNK_W - 1, 0, chunk->z * CHUNK_D - 1); chunks->getVoxels(voxelsBuffer); overflow = false; - offset = 0; + vertexOffset = 0; + indexOffset = indexSize = 0; const voxel* voxels = chunk->voxels; render(voxels, atlas_size); const vattr attrs[]{ {3}, {2}, {4}, {0} }; - Mesh* mesh = new Mesh(buffer, offset / VERTEX_SIZE, attrs); + Mesh* mesh = new Mesh(vertexBuffer, vertexOffset / VERTEX_SIZE, indexBuffer, indexSize, attrs); return mesh; } diff --git a/src/graphics/BlocksRenderer.h b/src/graphics/BlocksRenderer.h index d8c43164..03c0d412 100644 --- a/src/graphics/BlocksRenderer.h +++ b/src/graphics/BlocksRenderer.h @@ -15,43 +15,46 @@ class VoxelsVolume; class ChunksStorage; class BlocksRenderer { - float* buffer; - size_t offset; + float* vertexBuffer; + int* indexBuffer; + size_t vertexOffset; + size_t indexOffset, indexSize; size_t capacity; bool overflow = false; const Chunk* chunk = nullptr; VoxelsVolume* voxelsBuffer; - - void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); - void face(const glm::vec3& coord, float w, float h, - const glm::vec3& axisX, - const glm::vec3& axisY, - const UVRegion& region, - const glm::vec4 (&lights)[4], - const glm::vec4& tint); + void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); + void index(int a, int b, int c, int d, int e, int f); void face(const glm::vec3& coord, float w, float h, const glm::vec3& axisX, const glm::vec3& axisY, const UVRegion& region, - const glm::vec4 (&lights)[4], + const glm::vec4(&lights)[4], + const glm::vec4& tint); + + void face(const glm::vec3& coord, float w, float h, + const glm::vec3& axisX, + const glm::vec3& axisY, + const UVRegion& region, + const glm::vec4(&lights)[4], const glm::vec4& tint, bool rotated); void face(const glm::vec3& coord, float w, float h, - const glm::vec3& axisX, - const glm::vec3& axisY, - const UVRegion& region, - const glm::vec4 (&lights)[4]) { + const glm::vec3& axisX, + const glm::vec3& axisY, + const UVRegion& region, + const glm::vec4(&lights)[4]) { face(coord, w, h, axisX, axisY, region, lights, glm::vec4(1.0f)); } - void cube(const glm::vec3& coord, const glm::vec3& size, const UVRegion (&faces)[6]); - void blockCube(int x, int y, int z, const glm::vec3& size, const UVRegion (&faces)[6], ubyte group); - void blockCubeShaded(int x, int y, int z, const glm::vec3& size, const UVRegion (&faces)[6], const Block* block, ubyte states); + void cube(const glm::vec3& coord, const glm::vec3& size, const UVRegion(&faces)[6]); + void blockCube(int x, int y, int z, const glm::vec3& size, const UVRegion(&faces)[6], ubyte group); + void blockCubeShaded(int x, int y, int z, const glm::vec3& size, const UVRegion(&faces)[6], const Block* block, ubyte states); void blockXSprite(int x, int y, int z, const glm::vec3& size, const UVRegion& face1, const UVRegion& face2, float spread); bool isOpenForLight(int x, int y, int z) const; diff --git a/src/graphics/Mesh.cpp b/src/graphics/Mesh.cpp index c89cf5f0..4e42f3fd 100644 --- a/src/graphics/Mesh.cpp +++ b/src/graphics/Mesh.cpp @@ -3,28 +3,25 @@ int Mesh::meshesCount = 0; -Mesh::Mesh(const float* buffer, size_t vertices, const vattr* attrs) : vertices(vertices){ +Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs) : + vertices(vertices), + indices(indices), + ibo(0) +{ meshesCount++; vertexSize = 0; - for (int i = 0; attrs[i].size; i++){ + for (int i = 0; attrs[i].size; i++) { vertexSize += attrs[i].size; } glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - if (buffer){ - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, buffer, GL_STATIC_DRAW); - } else { - glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STATIC_DRAW); - } - + reload(vertexBuffer, vertices, indexBuffer, indices); // attributes int offset = 0; - for (int i = 0; attrs[i].size; i++){ + for (int i = 0; attrs[i].size; i++) { int size = attrs[i].size; glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float))); glEnableVertexAttribArray(i); @@ -38,18 +35,38 @@ Mesh::~Mesh(){ meshesCount--; glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); + if (ibo != 0) glDeleteBuffers(1, &ibo); } -void Mesh::reload(const float* buffer, size_t vertices){ +void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices){ glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, buffer, GL_STATIC_DRAW); + if (vertexBuffer != nullptr && vertices != 0) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STATIC_DRAW); + } + else { + glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STATIC_DRAW); + } + if (indexBuffer != nullptr && indices != 0) { + if (ibo == 0) glGenBuffers(1, &ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices, indexBuffer, GL_STATIC_DRAW); + } + else if (ibo != 0) { + glDeleteBuffers(1, &ibo); + } this->vertices = vertices; + this->indices = indices; } void Mesh::draw(unsigned int primitive){ glBindVertexArray(vao); - glDrawArrays(primitive, 0, vertices); + if (ibo != 0) { + glDrawElements(primitive, indices, GL_UNSIGNED_INT, 0); + } + else { + glDrawArrays(primitive, 0, vertices); + } glBindVertexArray(0); } diff --git a/src/graphics/Mesh.h b/src/graphics/Mesh.h index 58839ba2..4f274222 100644 --- a/src/graphics/Mesh.h +++ b/src/graphics/Mesh.h @@ -11,13 +11,17 @@ struct vattr { class Mesh { unsigned int vao; unsigned int vbo; + unsigned int ibo; size_t vertices; + size_t indices; size_t vertexSize; public: - Mesh(const float* buffer, size_t vertices, const vattr* attrs); + Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs); + Mesh(const float* vertexBuffer, size_t vertices, const vattr* attrs) : + Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; ~Mesh(); - void reload(const float* buffer, size_t vertices); + void reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0); void draw(unsigned int primitive); void draw(); diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp index 00203474..05d82244 100644 --- a/src/voxel_engine.cpp +++ b/src/voxel_engine.cpp @@ -95,7 +95,7 @@ int main() { if (std::filesystem::is_regular_file(settings_file)) { std::cout << "-- loading settings" << std::endl; std::string content = files::read_string(settings_file); - toml::Reader reader(&wrapper, settings_file, content); + toml::Reader reader(&wrapper, settings_file.string(), content); reader.read(); } Engine engine(settings);