diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index bf55ef12..25e8997d 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -12,6 +12,8 @@ #include +#include "util/timeutil.hpp" + const uint BlocksRenderer::VERTEX_SIZE = 6; const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); @@ -433,21 +435,9 @@ glm::vec4 BlocksRenderer::pickSoftLight( right, up); } -void BlocksRenderer::render(const voxel* voxels) { - int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); - int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); - - int beginEnds[256][2] {}; - for (int i = totalBegin; i < totalEnd; i++) { - const voxel& vox = voxels[i]; - blockid_t id = vox.id; - const auto& def = *blockDefsCache[id]; - - if (beginEnds[def.drawGroup][0] == 0) { - beginEnds[def.drawGroup][0] = i+1; - } - beginEnds[def.drawGroup][1] = i; - } +void BlocksRenderer::render( + const voxel* voxels, int beginEnds[256][2] +) { for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -462,13 +452,13 @@ void BlocksRenderer::render(const voxel* voxels) { if (id == 0 || def.drawGroup != drawGroup || state.segment) { continue; } + //if (def.translucent) { + // continue; + //} const UVRegion texfaces[6] { - cache.getRegion(id, 0), - cache.getRegion(id, 1), - cache.getRegion(id, 2), - cache.getRegion(id, 3), - cache.getRegion(id, 4), - cache.getRegion(id, 5) + cache.getRegion(id, 0), cache.getRegion(id, 1), + cache.getRegion(id, 2), cache.getRegion(id, 3), + cache.getRegion(id, 4), cache.getRegion(id, 5) }; int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); @@ -503,43 +493,143 @@ void BlocksRenderer::render(const voxel* voxels) { } } +SortingMeshData BlocksRenderer::renderTranslucent( + const voxel* voxels, int beginEnds[256][2] +) { + timeutil::ScopeLogTimer log(555); + SortingMeshData sortingMesh {{}}; + + for (const auto drawGroup : *content.drawGroups) { + int begin = beginEnds[drawGroup][0]; + if (begin == 0) { + continue; + } + int end = beginEnds[drawGroup][1]; + for (int i = begin-1; i <= end; i++) { + const voxel& vox = voxels[i]; + blockid_t id = vox.id; + blockstate state = vox.state; + const auto& def = *blockDefsCache[id]; + if (id == 0 || def.drawGroup != drawGroup || state.segment) { + continue; + } + if (!def.translucent) { + continue; + } + const UVRegion texfaces[6] { + cache.getRegion(id, 0), cache.getRegion(id, 1), + cache.getRegion(id, 2), cache.getRegion(id, 3), + cache.getRegion(id, 4), cache.getRegion(id, 5) + }; + int x = i % CHUNK_W; + int y = i / (CHUNK_D * CHUNK_W); + int z = (i / CHUNK_D) % CHUNK_W; + switch (def.model) { + case BlockModel::block: + blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, + def.ambientOcclusion); + break; + case BlockModel::xsprite: { + blockXSprite(x, y, z, glm::vec3(1.0f), + texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); + break; + } + case BlockModel::aabb: { + blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); + break; + } + case BlockModel::custom: { + blockCustomModel({x, y, z}, &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); + break; + } + default: + break; + } + if (vertexOffset == 0) { + continue; + } + SortingMeshEntry entry {glm::vec3( + x + chunk->x * CHUNK_W, y, z + chunk->z * CHUNK_D + ), util::Buffer(indexSize * VERTEX_SIZE)}; + + for (int j = 0; j < indexSize; j++) { + std::memcpy( + entry.vertexData.data(), + vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE, + sizeof(float) * VERTEX_SIZE + ); + } + sortingMesh.entries.push_back(std::move(entry)); + vertexOffset = 0; + indexOffset = indexSize = 0; + } + } + return sortingMesh; +} + void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { this->chunk = chunk; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, chunk->z * CHUNK_D - voxelBufferPadding); chunks->getVoxels(voxelsBuffer.get(), settings.graphics.backlight.get()); - overflow = false; - vertexOffset = 0; - indexOffset = indexSize = 0; + if (voxelsBuffer->pickBlockId( chunk->x * CHUNK_W, 0, chunk->z * CHUNK_D ) == BLOCK_VOID) { cancelled = true; return; } - cancelled = false; const voxel* voxels = chunk->voxels; - render(voxels); + + int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); + int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); + + int beginEnds[256][2] {}; + for (int i = totalBegin; i < totalEnd; i++) { + const voxel& vox = voxels[i]; + blockid_t id = vox.id; + const auto& def = *blockDefsCache[id]; + + if (beginEnds[def.drawGroup][0] == 0) { + beginEnds[def.drawGroup][0] = i+1; + } + beginEnds[def.drawGroup][1] = i; + } + cancelled = false; + + overflow = false; + vertexOffset = 0; + indexOffset = indexSize = 0; + + sortingMesh = std::move(renderTranslucent(voxels, beginEnds)); + + overflow = false; + vertexOffset = 0; + indexOffset = indexSize = 0; + + render(voxels, beginEnds); } -MeshData BlocksRenderer::createMesh() { +ChunkMeshData BlocksRenderer::createMesh() { const vattr attrs[]{ {3}, {2}, {1}, {0} }; - return MeshData( + return ChunkMeshData{MeshData( util::Buffer(vertexBuffer.get(), vertexOffset), util::Buffer(indexBuffer.get(), indexSize), util::Buffer({{3}, {2}, {1}, {0}}) - ); + ), std::move(sortingMesh)}; } -std::shared_ptr BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { +ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { build(chunk, chunks); const vattr attrs[]{ {3}, {2}, {1}, {0} }; size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE; - return std::make_shared( + return ChunkMesh{std::make_shared( vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs - ); + ), std::move(sortingMesh)}; } VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const { diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 828ddf7d..cdb20749 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -12,6 +12,7 @@ #include "voxels/VoxelsVolume.hpp" #include "graphics/core/MeshData.hpp" #include "maths/util.hpp" +#include "commons.hpp" class Content; class Mesh; @@ -45,6 +46,8 @@ class BlocksRenderer { util::PseudoRandom randomizer; + SortingMeshData sortingMesh; + 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); @@ -115,7 +118,6 @@ class BlocksRenderer { bool isOpenForLight(int x, int y, int z) const; - // Does block allow to see other blocks sides (is it transparent) inline bool isOpen(const glm::ivec3& pos, ubyte group) const { auto id = voxelsBuffer->pickBlockId( @@ -135,7 +137,9 @@ class BlocksRenderer { glm::vec4 pickLight(const glm::ivec3& coord) const; glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const; glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const; - void render(const voxel* voxels); + + void render(const voxel* voxels, int beginEnds[256][2]); + SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]); public: BlocksRenderer( size_t capacity, @@ -146,8 +150,8 @@ public: virtual ~BlocksRenderer(); void build(const Chunk* chunk, const Chunks* chunks); - std::shared_ptr render(const Chunk* chunk, const Chunks* chunks); - MeshData createMesh(); + ChunkMesh render(const Chunk* chunk, const Chunks* chunks); + ChunkMeshData createMesh(); VoxelsVolume* getVoxelsBuffer() const; bool isCancelled() const { diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index d0ae56b4..847163fc 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -62,7 +62,11 @@ ChunksRenderer::ChunksRenderer( [&](){return std::make_shared(*level, cache, settings);}, [&](RendererResult& result){ if (!result.cancelled) { - meshes[result.key] = std::make_shared(result.meshData); + auto meshData = std::move(result.meshData); + meshes[result.key] = ChunkMesh { + std::make_shared(meshData.mesh), + std::move(meshData.sortingMesh) + }; } inwork.erase(result.key); }, settings.graphics.chunkMaxRenderers.get()) @@ -82,8 +86,10 @@ std::shared_ptr ChunksRenderer::render(const std::shared_ptr& chunk chunk->flags.modified = false; if (important) { auto mesh = renderer->render(chunk.get(), level.chunks.get()); - meshes[glm::ivec2(chunk->x, chunk->z)] = mesh; - return mesh; + meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { + std::move(mesh.mesh), std::move(mesh.sortingMesh) + }; + return meshes[glm::ivec2(chunk->x, chunk->z)].mesh; } glm::ivec2 key(chunk->x, chunk->z); if (inwork.find(key) != inwork.end()) { @@ -115,7 +121,7 @@ std::shared_ptr ChunksRenderer::getOrRender(const std::shared_ptr& if (chunk->flags.modified) { render(chunk, important); } - return found->second; + return found->second.mesh; } void ChunksRenderer::update() { diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index c08266bb..e44940ea 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -10,6 +10,7 @@ #include "voxels/ChunksStorage.hpp" #include "util/ThreadPool.hpp" #include "graphics/core/MeshData.hpp" +#include "commons.hpp" class Mesh; class Chunk; @@ -35,7 +36,7 @@ struct ChunksSortEntry { struct RendererResult { glm::ivec2 key; bool cancelled; - MeshData meshData; + ChunkMeshData meshData; }; class ChunksRenderer { @@ -45,7 +46,7 @@ class ChunksRenderer { const EngineSettings& settings; std::unique_ptr renderer; - std::unordered_map> meshes; + std::unordered_map meshes; std::unordered_map inwork; std::vector indices; util::ThreadPool, RendererResult> threadPool; diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp new file mode 100644 index 00000000..4101f8a8 --- /dev/null +++ b/src/graphics/render/commons.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include "graphics/core/MeshData.hpp" +#include "util/Buffer.hpp" + +class Mesh; + +struct SortingMeshEntry { + glm::vec3 position; + util::Buffer vertexData; +}; + +struct SortingMeshData { + std::vector entries; +}; + +struct ChunkMeshData { + MeshData mesh; + SortingMeshData sortingMesh; +}; + +struct ChunkMesh { + std::shared_ptr mesh; + SortingMeshData sortingMesh; +};