mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-12 14:31:50 +00:00
stabilize delays of chunks meshes building
This commit is contained in:
parent
f47ccd5f30
commit
88544183d0
13 changed files with 335 additions and 191 deletions
|
|
@ -353,7 +353,7 @@ std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
|
||||||
auto pool =
|
auto pool =
|
||||||
std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>(
|
std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>(
|
||||||
"assets-loader-pool",
|
"assets-loader-pool",
|
||||||
[=]() { return std::make_shared<LoaderWorker>(this); },
|
[=]() { return std::make_unique<LoaderWorker>(this); },
|
||||||
[this](assetload::postfunc&& func) { func(&assets); }
|
[this](assetload::postfunc&& func) { func(&assets); }
|
||||||
);
|
);
|
||||||
pool->setOnComplete(std::move(onDone));
|
pool->setOnComplete(std::move(onDone));
|
||||||
|
|
|
||||||
|
|
@ -42,21 +42,22 @@ void BlocksRenderer::vertex(
|
||||||
const glm::vec3& normal,
|
const glm::vec3& normal,
|
||||||
float emission
|
float emission
|
||||||
) {
|
) {
|
||||||
vertexBuffer[vertexCount].position = coord;
|
|
||||||
|
|
||||||
vertexBuffer[vertexCount].uv = {u,v};
|
vertexBuffer[vertexCount++] = {
|
||||||
|
coord,
|
||||||
vertexBuffer[vertexCount].normal[0] = static_cast<uint8_t>(normal.r * 127 + 128);
|
{u, v},
|
||||||
vertexBuffer[vertexCount].normal[1] = static_cast<uint8_t>(normal.g * 127 + 128);
|
{
|
||||||
vertexBuffer[vertexCount].normal[2] = static_cast<uint8_t>(normal.b * 127 + 128);
|
static_cast<uint8_t>(light.r * 255),
|
||||||
vertexBuffer[vertexCount].normal[3] = static_cast<uint8_t>(emission * 255);
|
static_cast<uint8_t>(light.g * 255),
|
||||||
|
static_cast<uint8_t>(light.b * 255),
|
||||||
vertexBuffer[vertexCount].color[0] = static_cast<uint8_t>(light.r * 255);
|
static_cast<uint8_t>(light.a * 255),
|
||||||
vertexBuffer[vertexCount].color[1] = static_cast<uint8_t>(light.g * 255);
|
}, {
|
||||||
vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
|
static_cast<uint8_t>(normal.x * 127 + 128),
|
||||||
vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
|
static_cast<uint8_t>(normal.y * 127 + 128),
|
||||||
|
static_cast<uint8_t>(normal.z * 127 + 128),
|
||||||
vertexCount++;
|
static_cast<uint8_t>(emission * 255)
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) {
|
void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) {
|
||||||
|
|
@ -434,28 +435,11 @@ void BlocksRenderer::blockCube(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
|
|
||||||
blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x,
|
|
||||||
y,
|
|
||||||
chunk->z * CHUNK_D + z);
|
|
||||||
if (id == BLOCK_VOID) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const Block& block = *blockDefsCache[id];
|
|
||||||
if (block.lightPassing) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return !id;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const {
|
glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const {
|
||||||
if (isOpenForLight(x, y, z)) {
|
light_t light = voxelsBuffer->pickLight(
|
||||||
light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y,
|
chunk->x * CHUNK_W + x, y, chunk->z * CHUNK_D + z
|
||||||
chunk->z * CHUNK_D + z);
|
);
|
||||||
return Lightmap::extractNormalized(light);
|
return light ? Lightmap::extractNormalized(light) : glm::vec4(0.0f);
|
||||||
} else {
|
|
||||||
return glm::vec4(0.0f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 BlocksRenderer::pickLight(const glm::ivec3& coord) const {
|
glm::vec4 BlocksRenderer::pickLight(const glm::ivec3& coord) const {
|
||||||
|
|
@ -694,7 +678,9 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
||||||
return sortingMesh;
|
return sortingMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksRenderer::build(const Chunk* chunk, const VoxelsVolume& volume) {
|
void BlocksRenderer::build(
|
||||||
|
const Chunk* chunk, const VoxelsRenderVolume& volume
|
||||||
|
) {
|
||||||
this->chunk = chunk;
|
this->chunk = chunk;
|
||||||
this->voxelsBuffer = &volume;
|
this->voxelsBuffer = &volume;
|
||||||
if (voxelsBuffer->pickBlockId(
|
if (voxelsBuffer->pickBlockId(
|
||||||
|
|
@ -707,16 +693,17 @@ void BlocksRenderer::build(const Chunk* chunk, const VoxelsVolume& volume) {
|
||||||
|
|
||||||
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D);
|
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D);
|
||||||
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D);
|
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D);
|
||||||
|
bool hasTranslucent = false;
|
||||||
int beginEnds[256][2] {};
|
int beginEnds[256][2] {};
|
||||||
for (int i = totalBegin; i < totalEnd; i++) {
|
for (int i = totalBegin; i < totalEnd; i++) {
|
||||||
const voxel& vox = voxels[i];
|
const voxel& vox = voxels[i];
|
||||||
blockid_t id = vox.id;
|
blockid_t id = vox.id;
|
||||||
const auto& def = *blockDefsCache[id];
|
const auto& def = *blockDefsCache[id];
|
||||||
const auto& variant = def.getVariantByBits(vox.state.userbits);
|
const auto& variant = def.getVariantByBits(vox.state.userbits);
|
||||||
|
hasTranslucent = def.translucent || hasTranslucent;
|
||||||
|
|
||||||
if (beginEnds[variant.drawGroup][0] == 0) {
|
if (beginEnds[variant.drawGroup][0] == 0) {
|
||||||
beginEnds[variant.drawGroup][0] = i+1;
|
beginEnds[variant.drawGroup][0] = i + 1;
|
||||||
}
|
}
|
||||||
beginEnds[variant.drawGroup][1] = i;
|
beginEnds[variant.drawGroup][1] = i;
|
||||||
}
|
}
|
||||||
|
|
@ -729,7 +716,11 @@ void BlocksRenderer::build(const Chunk* chunk, const VoxelsVolume& volume) {
|
||||||
denseRender = false;
|
denseRender = false;
|
||||||
densePass = false;
|
densePass = false;
|
||||||
|
|
||||||
sortingMesh = renderTranslucent(voxels, beginEnds);
|
if (hasTranslucent) {
|
||||||
|
sortingMesh = renderTranslucent(voxels, beginEnds);
|
||||||
|
} else {
|
||||||
|
sortingMesh = {};
|
||||||
|
}
|
||||||
|
|
||||||
overflow = false;
|
overflow = false;
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
|
|
@ -775,7 +766,7 @@ ChunkMeshData BlocksRenderer::createMesh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkMesh BlocksRenderer::render(
|
ChunkMesh BlocksRenderer::render(
|
||||||
const Chunk* chunk, const VoxelsVolume& volume
|
const Chunk* chunk, const VoxelsRenderVolume& volume
|
||||||
) {
|
) {
|
||||||
build(chunk, volume);
|
build(chunk, volume);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ class Content;
|
||||||
class Block;
|
class Block;
|
||||||
class Chunk;
|
class Chunk;
|
||||||
class Chunks;
|
class Chunks;
|
||||||
class VoxelsVolume;
|
|
||||||
class ContentGfxCache;
|
class ContentGfxCache;
|
||||||
struct UVRegion;
|
struct UVRegion;
|
||||||
|
|
||||||
|
|
@ -31,9 +30,9 @@ public:
|
||||||
);
|
);
|
||||||
~BlocksRenderer();
|
~BlocksRenderer();
|
||||||
|
|
||||||
void build(const Chunk* chunk, const VoxelsVolume& volume);
|
void build(const Chunk* chunk, const VoxelsRenderVolume& volume);
|
||||||
ChunkMesh render(
|
ChunkMesh render(
|
||||||
const Chunk* chunk, const VoxelsVolume& volume
|
const Chunk* chunk, const VoxelsRenderVolume& volume
|
||||||
);
|
);
|
||||||
ChunkMeshData createMesh();
|
ChunkMeshData createMesh();
|
||||||
|
|
||||||
|
|
@ -58,7 +57,7 @@ private:
|
||||||
bool densePass = false;
|
bool densePass = false;
|
||||||
bool denseRender = false;
|
bool denseRender = false;
|
||||||
const Chunk* chunk = nullptr;
|
const Chunk* chunk = nullptr;
|
||||||
const VoxelsVolume* voxelsBuffer = nullptr;
|
const VoxelsRenderVolume* voxelsBuffer = nullptr;
|
||||||
|
|
||||||
const Block* const* blockDefsCache;
|
const Block* const* blockDefsCache;
|
||||||
const ContentGfxCache& cache;
|
const ContentGfxCache& cache;
|
||||||
|
|
@ -143,8 +142,6 @@ private:
|
||||||
bool ao
|
bool ao
|
||||||
);
|
);
|
||||||
|
|
||||||
bool isOpenForLight(int x, int y, int z) const;
|
|
||||||
|
|
||||||
// Does block allow to see other blocks sides (is it transparent)
|
// Does block allow to see other blocks sides (is it transparent)
|
||||||
inline bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
|
inline bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
|
||||||
auto vox = voxelsBuffer->pickBlock(
|
auto vox = voxelsBuffer->pickBlock(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ static debug::Logger logger("chunks-render");
|
||||||
|
|
||||||
size_t ChunksRenderer::visibleChunks = 0;
|
size_t ChunksRenderer::visibleChunks = 0;
|
||||||
|
|
||||||
|
static constexpr inline size_t MAX_CHUNKS_ENQUEUED_IN_FRAME = 4;
|
||||||
|
|
||||||
class RendererWorker : public util::Worker<RendererJob, RendererResult> {
|
class RendererWorker : public util::Worker<RendererJob, RendererResult> {
|
||||||
BlocksRenderer renderer;
|
BlocksRenderer renderer;
|
||||||
public:
|
public:
|
||||||
|
|
@ -51,8 +53,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static util::ObjectsPool<VoxelsVolume> voxelsVolumesPool {};
|
static util::ObjectsPool<VoxelsRenderVolume> voxelsVolumesPool {};
|
||||||
static inline const int VOXELS_BUFFER_PADDING = 2;
|
|
||||||
|
|
||||||
ChunksRenderer::ChunksRenderer(
|
ChunksRenderer::ChunksRenderer(
|
||||||
const Level* level,
|
const Level* level,
|
||||||
|
|
@ -69,7 +70,7 @@ ChunksRenderer::ChunksRenderer(
|
||||||
threadPool(
|
threadPool(
|
||||||
"chunks-render-pool",
|
"chunks-render-pool",
|
||||||
[&]() {
|
[&]() {
|
||||||
return std::make_shared<RendererWorker>(
|
return std::make_unique<RendererWorker>(
|
||||||
*level, cache, settings
|
*level, cache, settings
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -105,14 +106,10 @@ ChunksRenderer::ChunksRenderer(
|
||||||
|
|
||||||
ChunksRenderer::~ChunksRenderer() = default;
|
ChunksRenderer::~ChunksRenderer() = default;
|
||||||
|
|
||||||
std::shared_ptr<VoxelsVolume> ChunksRenderer::prepareVoxelsVolume(
|
std::shared_ptr<VoxelsRenderVolume> ChunksRenderer::prepareVoxelsVolume(
|
||||||
const Chunk& chunk
|
const Chunk& chunk
|
||||||
) {
|
) {
|
||||||
auto voxelsBuffer = voxelsVolumesPool.create(
|
auto voxelsBuffer = voxelsVolumesPool.create();
|
||||||
CHUNK_W + VOXELS_BUFFER_PADDING * 2,
|
|
||||||
CHUNK_H,
|
|
||||||
CHUNK_D + VOXELS_BUFFER_PADDING * 2
|
|
||||||
);
|
|
||||||
voxelsBuffer->setPosition(
|
voxelsBuffer->setPosition(
|
||||||
chunk.x * CHUNK_W - VOXELS_BUFFER_PADDING, 0,
|
chunk.x * CHUNK_W - VOXELS_BUFFER_PADDING, 0,
|
||||||
chunk.z * CHUNK_D - VOXELS_BUFFER_PADDING
|
chunk.z * CHUNK_D - VOXELS_BUFFER_PADDING
|
||||||
|
|
@ -123,8 +120,10 @@ std::shared_ptr<VoxelsVolume> ChunksRenderer::prepareVoxelsVolume(
|
||||||
return voxelsBuffer;
|
return voxelsBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "util/timeutil.hpp"
|
||||||
|
|
||||||
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, bool lowPriority
|
||||||
) {
|
) {
|
||||||
glm::ivec2 key(chunk->x, chunk->z);
|
glm::ivec2 key(chunk->x, chunk->z);
|
||||||
chunk->flags.modified = false;
|
chunk->flags.modified = false;
|
||||||
|
|
@ -136,16 +135,16 @@ const Mesh<ChunkVertex>* ChunksRenderer::render(
|
||||||
std::move(mesh.mesh), std::move(mesh.sortingMeshData), nullptr};
|
std::move(mesh.mesh), std::move(mesh.sortingMeshData), nullptr};
|
||||||
return meshes[key].mesh.get();
|
return meshes[key].mesh.get();
|
||||||
}
|
}
|
||||||
if (inwork.find(key) != inwork.end()) {
|
if (inwork.find(key) != inwork.end() ||
|
||||||
|
((inwork.size() >= threadPool.getWorkTotal() ||
|
||||||
|
enqueuedInFrame >= MAX_CHUNKS_ENQUEUED_IN_FRAME) &&
|
||||||
|
lowPriority)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
enqueuedInFrame++;
|
||||||
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
|
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
|
||||||
inwork[key] = true;
|
|
||||||
chunks.getVoxels(
|
|
||||||
*voxelsBuffer, settings.graphics.backlight.get(), chunk->top + 1
|
|
||||||
);
|
|
||||||
|
|
||||||
threadPool.enqueueJob({chunk, std::move(voxelsBuffer)});
|
threadPool.enqueueJob({chunk, std::move(voxelsBuffer)});
|
||||||
|
inwork[key] = true;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,20 +162,21 @@ void ChunksRenderer::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mesh<ChunkVertex>* ChunksRenderer::getOrRender(
|
const Mesh<ChunkVertex>* ChunksRenderer::getOrRender(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||||
) {
|
) {
|
||||||
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||||
if (found == meshes.end()) {
|
if (found == meshes.end()) {
|
||||||
return render(chunk, important);
|
return render(chunk, important, lowPriority);
|
||||||
}
|
}
|
||||||
if (chunk->flags.modified && chunk->flags.lighted) {
|
if (chunk->flags.modified && chunk->flags.lighted) {
|
||||||
render(chunk, important);
|
render(chunk, important, lowPriority);
|
||||||
}
|
}
|
||||||
return found->second.mesh.get();
|
return found->second.mesh.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunksRenderer::update() {
|
void ChunksRenderer::update() {
|
||||||
threadPool.pullResults();
|
threadPool.pullResults();
|
||||||
|
enqueuedInFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||||
|
|
@ -202,7 +202,11 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||||
(chunk->z + 0.5f) * CHUNK_D
|
(chunk->z + 0.5f) * CHUNK_D
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
auto mesh = getOrRender(chunk, distance < CHUNK_W * 1.5f);
|
auto mesh = getOrRender(
|
||||||
|
chunk,
|
||||||
|
distance < CHUNK_W * 1.5f,
|
||||||
|
distance > CHUNK_W * settings.chunks.loadDistance.get() * 0.5
|
||||||
|
);
|
||||||
if (mesh == nullptr) {
|
if (mesh == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ class Chunks;
|
||||||
class Frustum;
|
class Frustum;
|
||||||
class BlocksRenderer;
|
class BlocksRenderer;
|
||||||
class ContentGfxCache;
|
class ContentGfxCache;
|
||||||
class VoxelsVolume;
|
|
||||||
struct EngineSettings;
|
struct EngineSettings;
|
||||||
|
|
||||||
struct ChunksSortEntry {
|
struct ChunksSortEntry {
|
||||||
|
|
@ -41,7 +40,7 @@ struct RendererResult {
|
||||||
|
|
||||||
struct RendererJob {
|
struct RendererJob {
|
||||||
std::shared_ptr<Chunk> chunk;
|
std::shared_ptr<Chunk> chunk;
|
||||||
std::shared_ptr<VoxelsVolume> volume;
|
std::shared_ptr<VoxelsRenderVolume> volume;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChunksRenderer {
|
class ChunksRenderer {
|
||||||
|
|
@ -58,7 +57,8 @@ class ChunksRenderer {
|
||||||
const Mesh<ChunkVertex>* retrieveChunk(
|
const Mesh<ChunkVertex>* retrieveChunk(
|
||||||
size_t index, const Camera& camera, bool culling
|
size_t index, const Camera& camera, bool culling
|
||||||
);
|
);
|
||||||
std::shared_ptr<VoxelsVolume> prepareVoxelsVolume(const Chunk& chunk);
|
std::shared_ptr<VoxelsRenderVolume> prepareVoxelsVolume(const Chunk& chunk);
|
||||||
|
size_t enqueuedInFrame = 0;
|
||||||
public:
|
public:
|
||||||
ChunksRenderer(
|
ChunksRenderer(
|
||||||
const Level* level,
|
const Level* level,
|
||||||
|
|
@ -71,13 +71,13 @@ public:
|
||||||
virtual ~ChunksRenderer();
|
virtual ~ChunksRenderer();
|
||||||
|
|
||||||
const Mesh<ChunkVertex>* render(
|
const Mesh<ChunkVertex>* render(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||||
);
|
);
|
||||||
void unload(const Chunk* chunk);
|
void unload(const Chunk* chunk);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
const Mesh<ChunkVertex>* getOrRender(
|
const Mesh<ChunkVertex>* getOrRender(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||||
);
|
);
|
||||||
|
|
||||||
void drawShadowsPass(
|
void drawShadowsPass(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "constants.hpp"
|
||||||
#include "graphics/core/MeshData.hpp"
|
#include "graphics/core/MeshData.hpp"
|
||||||
#include "util/Buffer.hpp"
|
#include "util/Buffer.hpp"
|
||||||
|
|
||||||
|
|
@ -51,3 +52,12 @@ struct ChunkMesh {
|
||||||
SortingMeshData sortingMeshData;
|
SortingMeshData sortingMeshData;
|
||||||
std::unique_ptr<Mesh<ChunkVertex> > sortedMesh;
|
std::unique_ptr<Mesh<ChunkVertex> > sortedMesh;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline constexpr int VOXELS_BUFFER_PADDING = 2;
|
||||||
|
|
||||||
|
template<int, int, int> class StaticVoxelsVolume;
|
||||||
|
|
||||||
|
using VoxelsRenderVolume = StaticVoxelsVolume<
|
||||||
|
CHUNK_W + VOXELS_BUFFER_PADDING * 2,
|
||||||
|
CHUNK_H,
|
||||||
|
CHUNK_D + VOXELS_BUFFER_PADDING * 2>;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ namespace util {
|
||||||
size_t countTotal() const {
|
size_t countTotal() const {
|
||||||
return objects.size();
|
return objects.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t countFree() const {
|
||||||
|
return freeObjects.size();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<void, AlignedDeleter>> objects;
|
std::vector<std::unique_ptr<void, AlignedDeleter>> objects;
|
||||||
std::queue<void*> freeObjects;
|
std::queue<void*> freeObjects;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace util {
|
||||||
bool standaloneResults = true;
|
bool standaloneResults = true;
|
||||||
bool stopOnFail = true;
|
bool stopOnFail = true;
|
||||||
|
|
||||||
void threadLoop(int index, std::shared_ptr<Worker<T, R>> worker) {
|
void threadLoop(int index, std::unique_ptr<Worker<T, R>> worker) {
|
||||||
std::condition_variable variable;
|
std::condition_variable variable;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
bool locked = false;
|
bool locked = false;
|
||||||
|
|
@ -76,7 +76,7 @@ namespace util {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(resultsMutex);
|
std::lock_guard<std::mutex> lock(resultsMutex);
|
||||||
results.push(ThreadPoolResult<T, R> {
|
results.push(ThreadPoolResult<T, R> {
|
||||||
job, variable, index, locked, result});
|
job, variable, index, locked, std::move(result)});
|
||||||
if (!standaloneResults) {
|
if (!standaloneResults) {
|
||||||
locked = true;
|
locked = true;
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +115,7 @@ namespace util {
|
||||||
/// unlimited, -2 is half of auto count, -4 is quarter.
|
/// unlimited, -2 is half of auto count, -4 is quarter.
|
||||||
ThreadPool(
|
ThreadPool(
|
||||||
std::string name,
|
std::string name,
|
||||||
supplier<std::shared_ptr<Worker<T, R>>> workersSupplier,
|
supplier<std::unique_ptr<Worker<T, R>>> workersSupplier,
|
||||||
consumer<R&&> resultConsumer,
|
consumer<R&&> resultConsumer,
|
||||||
int maxWorkers=UNLIMITED
|
int maxWorkers=UNLIMITED
|
||||||
)
|
)
|
||||||
|
|
@ -236,7 +236,7 @@ namespace util {
|
||||||
return resultsProcessed;
|
return resultsProcessed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void enqueueJob(T job) {
|
void enqueueJob(T&& job) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(jobsMutex);
|
std::lock_guard<std::mutex> lock(jobsMutex);
|
||||||
jobs.push(std::move(job));
|
jobs.push(std::move(job));
|
||||||
|
|
|
||||||
|
|
@ -335,26 +335,106 @@ bool Chunks::putChunk(const std::shared_ptr<Chunk>& chunk) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce nesting on next modification
|
static void fill_with_void(
|
||||||
// 25.06.2024: not now
|
voxel* voxels,
|
||||||
// 11.11.2024: not now
|
light_t* lights,
|
||||||
// 12.12.2025: not now
|
const glm::ivec3& pos,
|
||||||
void Chunks::getVoxels(VoxelsVolume& volume, bool backlight, int top) const {
|
const glm::ivec3& size,
|
||||||
voxel* voxels = volume.getVoxels();
|
int cx,
|
||||||
light_t* lights = volume.getLights();
|
int cz
|
||||||
int x = volume.getX();
|
) {
|
||||||
int y = volume.getY();
|
for (int ly = pos.y; ly < pos.y + size.y; ly++) {
|
||||||
int z = volume.getZ();
|
for (int lz = std::max(pos.z, cz * CHUNK_D);
|
||||||
|
lz < std::min(pos.z + size.z, (cz + 1) * CHUNK_D);
|
||||||
|
lz++) {
|
||||||
|
for (int lx = std::max(pos.x, cx * CHUNK_W);
|
||||||
|
lx < std::min(pos.x + size.x, (cx + 1) * CHUNK_W);
|
||||||
|
lx++) {
|
||||||
|
uint idx = vox_index(
|
||||||
|
lx - pos.x, ly - pos.y, lz - pos.z, size.x, size.z
|
||||||
|
);
|
||||||
|
voxels[idx].id = BLOCK_VOID;
|
||||||
|
lights[idx] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int w = volume.getW();
|
static inline light_t apply_backlight(light_t light) {
|
||||||
int h = std::min<int>(volume.getH(), top);
|
return Lightmap::combine(
|
||||||
int d = volume.getD();
|
std::min(15, Lightmap::extract(light, 0) + 1),
|
||||||
|
std::min(15, Lightmap::extract(light, 1) + 1),
|
||||||
|
std::min(15, Lightmap::extract(light, 2) + 1),
|
||||||
|
std::min(15, static_cast<int>(Lightmap::extract(light, 3)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
int scx = floordiv<CHUNK_W>(x);
|
#include "util/timeutil.hpp"
|
||||||
int scz = floordiv<CHUNK_D>(z);
|
|
||||||
|
|
||||||
int ecx = floordiv<CHUNK_W>(x + w);
|
// ugly
|
||||||
int ecz = floordiv<CHUNK_D>(z + d);
|
static inline void sample_chunk(
|
||||||
|
const decltype(ContentIndices::blocks)& defs,
|
||||||
|
const Chunk& chunk,
|
||||||
|
voxel* voxels,
|
||||||
|
light_t* lights,
|
||||||
|
const glm::ivec3& pos,
|
||||||
|
const glm::ivec3& size,
|
||||||
|
int cx,
|
||||||
|
int cz,
|
||||||
|
bool backlight
|
||||||
|
) {
|
||||||
|
const auto cvoxels = chunk.voxels;
|
||||||
|
const auto clights = chunk.lightmap ? chunk.lightmap->getLights() : nullptr;
|
||||||
|
for (int ly = pos.y; ly < pos.y + size.y; ly++) {
|
||||||
|
for (int lz = std::max(pos.z, cz * CHUNK_D);
|
||||||
|
lz < std::min(pos.z + size.z, (cz + 1) * CHUNK_D);
|
||||||
|
lz++) {
|
||||||
|
for (int lx = std::max(pos.x, cx * CHUNK_W);
|
||||||
|
lx < std::min(pos.x + size.x, (cx + 1) * CHUNK_W);
|
||||||
|
lx++) {
|
||||||
|
uint vidx = vox_index(
|
||||||
|
lx - pos.x, ly - pos.y, lz - pos.z, size.x, size.z
|
||||||
|
);
|
||||||
|
uint cidx = vox_index(
|
||||||
|
lx - cx * CHUNK_W,
|
||||||
|
ly,
|
||||||
|
lz - cz * CHUNK_D,
|
||||||
|
CHUNK_W,
|
||||||
|
CHUNK_D
|
||||||
|
);
|
||||||
|
auto& vox = voxels[vidx];
|
||||||
|
vox = cvoxels[cidx];
|
||||||
|
light_t light = clights ? clights[cidx]
|
||||||
|
: Lightmap::SUN_LIGHT_ONLY;
|
||||||
|
// todo: move to the BlocksRenderer
|
||||||
|
if (backlight) {
|
||||||
|
const auto block = defs.get(vox.id);
|
||||||
|
if (block && block->lightPassing) {
|
||||||
|
light = apply_backlight(light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lights[vidx] = light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunks::getVoxels(
|
||||||
|
voxel* voxels,
|
||||||
|
light_t* lights,
|
||||||
|
const glm::ivec3& pos,
|
||||||
|
const glm::ivec3& size,
|
||||||
|
bool backlight,
|
||||||
|
int top
|
||||||
|
) const {
|
||||||
|
timeutil::ScopeLogTimer log(111);
|
||||||
|
int h = std::min<int>(size.y, top);
|
||||||
|
|
||||||
|
int scx = floordiv<CHUNK_W>(pos.x);
|
||||||
|
int scz = floordiv<CHUNK_D>(pos.z);
|
||||||
|
|
||||||
|
int ecx = floordiv<CHUNK_W>(pos.x + size.x);
|
||||||
|
int ecz = floordiv<CHUNK_D>(pos.z + size.z);
|
||||||
|
|
||||||
int cw = ecx - scx + 1;
|
int cw = ecx - scx + 1;
|
||||||
int cd = ecz - scz + 1;
|
int cd = ecz - scz + 1;
|
||||||
|
|
@ -364,67 +444,37 @@ void Chunks::getVoxels(VoxelsVolume& volume, bool backlight, int top) const {
|
||||||
for (int cx = scx; cx < scx + cw; cx++) {
|
for (int cx = scx; cx < scx + cw; cx++) {
|
||||||
const auto chunk = getChunk(cx, cz);
|
const auto chunk = getChunk(cx, cz);
|
||||||
if (chunk == nullptr) {
|
if (chunk == nullptr) {
|
||||||
// no chunk loaded -> filling with BLOCK_VOID
|
fill_with_void(
|
||||||
for (int ly = y; ly < y + h; ly++) {
|
voxels, lights, pos, {size.x, h, size.z}, cx, cz
|
||||||
for (int lz = std::max(z, cz * CHUNK_D);
|
);
|
||||||
lz < std::min(z + d, (cz + 1) * CHUNK_D);
|
continue;
|
||||||
lz++) {
|
|
||||||
for (int lx = std::max(x, cx * CHUNK_W);
|
|
||||||
lx < std::min(x + w, (cx + 1) * CHUNK_W);
|
|
||||||
lx++) {
|
|
||||||
uint idx = vox_index(lx - x, ly - y, lz - z, w, d);
|
|
||||||
voxels[idx].id = BLOCK_VOID;
|
|
||||||
lights[idx] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const voxel* cvoxels = chunk->voxels;
|
|
||||||
const light_t* clights =
|
|
||||||
chunk->lightmap ? chunk->lightmap->getLights() : nullptr;
|
|
||||||
for (int ly = y; ly < y + h; ly++) {
|
|
||||||
for (int lz = std::max(z, cz * CHUNK_D);
|
|
||||||
lz < std::min(z + d, (cz + 1) * CHUNK_D);
|
|
||||||
lz++) {
|
|
||||||
for (int lx = std::max(x, cx * CHUNK_W);
|
|
||||||
lx < std::min(x + w, (cx + 1) * CHUNK_W);
|
|
||||||
lx++) {
|
|
||||||
uint vidx = vox_index(lx - x, ly - y, lz - z, w, d);
|
|
||||||
uint cidx = vox_index(
|
|
||||||
lx - cx * CHUNK_W,
|
|
||||||
ly,
|
|
||||||
lz - cz * CHUNK_D,
|
|
||||||
CHUNK_W,
|
|
||||||
CHUNK_D
|
|
||||||
);
|
|
||||||
voxels[vidx] = cvoxels[cidx];
|
|
||||||
light_t light = clights ? clights[cidx]
|
|
||||||
: Lightmap::SUN_LIGHT_ONLY;
|
|
||||||
if (backlight) {
|
|
||||||
const auto block =
|
|
||||||
indices.blocks.get(voxels[vidx].id);
|
|
||||||
if (block && block->lightPassing) {
|
|
||||||
light = Lightmap::combine(
|
|
||||||
std::min(15,
|
|
||||||
Lightmap::extract(light, 0) + 1),
|
|
||||||
std::min(15,
|
|
||||||
Lightmap::extract(light, 1) + 1),
|
|
||||||
std::min(15,
|
|
||||||
Lightmap::extract(light, 2) + 1),
|
|
||||||
std::min(15,
|
|
||||||
static_cast<int>(Lightmap::extract(light, 3)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lights[vidx] = light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
sample_chunk(
|
||||||
|
indices.blocks,
|
||||||
|
*chunk,
|
||||||
|
voxels,
|
||||||
|
lights,
|
||||||
|
pos,
|
||||||
|
{size.x, h, size.z},
|
||||||
|
cx,
|
||||||
|
cz,
|
||||||
|
backlight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chunks::getVoxels(VoxelsVolume& volume, bool backlight, int top) const {
|
||||||
|
getVoxels(
|
||||||
|
volume.getVoxels(),
|
||||||
|
volume.getLights(),
|
||||||
|
{volume.getX(), volume.getY(), volume.getZ()},
|
||||||
|
{volume.getW(), volume.getH(), volume.getD()},
|
||||||
|
backlight,
|
||||||
|
top
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void Chunks::saveAndClear() {
|
void Chunks::saveAndClear() {
|
||||||
areaMap.clear();
|
areaMap.clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ class LevelEvents;
|
||||||
class Block;
|
class Block;
|
||||||
class VoxelsVolume;
|
class VoxelsVolume;
|
||||||
|
|
||||||
|
template <int w, int h, int d> class StaticVoxelsVolume;
|
||||||
|
|
||||||
/// Player-centred chunks matrix
|
/// Player-centred chunks matrix
|
||||||
class Chunks {
|
class Chunks {
|
||||||
LevelEvents* events;
|
LevelEvents* events;
|
||||||
|
|
@ -128,7 +130,34 @@ public:
|
||||||
bool isReplaceableBlock(int32_t x, int32_t y, int32_t z);
|
bool isReplaceableBlock(int32_t x, int32_t y, int32_t z);
|
||||||
bool isObstacleBlock(int32_t x, int32_t y, int32_t z);
|
bool isObstacleBlock(int32_t x, int32_t y, int32_t z);
|
||||||
|
|
||||||
void getVoxels(VoxelsVolume& volume, bool backlight = false, int top = CHUNK_H) const;
|
void getVoxels(
|
||||||
|
VoxelsVolume& volume, bool backlight = false, int top = CHUNK_H
|
||||||
|
) const;
|
||||||
|
|
||||||
|
template <int w, int h, int d>
|
||||||
|
void getVoxels(
|
||||||
|
StaticVoxelsVolume<w, h, d>& volume,
|
||||||
|
bool backlight = false,
|
||||||
|
int top = CHUNK_H
|
||||||
|
) const {
|
||||||
|
getVoxels(
|
||||||
|
volume.getVoxels(),
|
||||||
|
volume.getLights(),
|
||||||
|
{volume.getX(), volume.getY(), volume.getZ()},
|
||||||
|
{w, h, d},
|
||||||
|
backlight,
|
||||||
|
top
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getVoxels(
|
||||||
|
voxel* voxels,
|
||||||
|
light_t* lights,
|
||||||
|
const glm::ivec3& pos,
|
||||||
|
const glm::ivec3& size,
|
||||||
|
bool backlight,
|
||||||
|
int top
|
||||||
|
) const;
|
||||||
|
|
||||||
void setCenter(int32_t x, int32_t z);
|
void setCenter(int32_t x, int32_t z);
|
||||||
void resize(uint32_t newW, uint32_t newD);
|
void resize(uint32_t newW, uint32_t newD);
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#include "VoxelsVolume.hpp"
|
|
||||||
|
|
||||||
VoxelsVolume::VoxelsVolume(int x, int y, int z, int w, int h, int d)
|
|
||||||
: x(x),
|
|
||||||
y(y),
|
|
||||||
z(z),
|
|
||||||
w(w),
|
|
||||||
h(h),
|
|
||||||
d(d),
|
|
||||||
voxels(std::make_unique<voxel[]>(w * h * d)),
|
|
||||||
lights(std::make_unique<light_t[]>(w * h * d)) {
|
|
||||||
for (int i = 0; i < w * h * d; i++) {
|
|
||||||
voxels[i].id = BLOCK_VOID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VoxelsVolume::VoxelsVolume(int w, int h, int d)
|
|
||||||
: VoxelsVolume(0, 0, 0, w, h, d) {
|
|
||||||
}
|
|
||||||
|
|
||||||
VoxelsVolume::~VoxelsVolume() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void VoxelsVolume::setPosition(int x, int y, int z) {
|
|
||||||
this->x = x;
|
|
||||||
this->y = y;
|
|
||||||
this->z = z;
|
|
||||||
}
|
|
||||||
|
|
@ -4,17 +4,25 @@
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "voxel.hpp"
|
#include "voxel.hpp"
|
||||||
|
|
||||||
class VoxelsVolume {
|
#include <cstring>
|
||||||
int x, y, z;
|
|
||||||
int w, h, d;
|
|
||||||
std::unique_ptr<voxel[]> voxels;
|
|
||||||
std::unique_ptr<light_t[]> lights;
|
|
||||||
public:
|
|
||||||
VoxelsVolume(int w, int h, int d);
|
|
||||||
VoxelsVolume(int x, int y, int z, int w, int h, int d);
|
|
||||||
virtual ~VoxelsVolume();
|
|
||||||
|
|
||||||
void setPosition(int x, int y, int z);
|
class VoxelsVolume {
|
||||||
|
public:
|
||||||
|
static inline constexpr size_t MAX_VOXELS = CHUNK_VOL * 2;
|
||||||
|
|
||||||
|
VoxelsVolume(int w, int h, int d)
|
||||||
|
: VoxelsVolume(0, 0, 0, w, h, d) {}
|
||||||
|
|
||||||
|
VoxelsVolume(int x, int y, int z, int w, int h, int d)
|
||||||
|
: x(x), y(y), z(z), w(w), h(h), d(d) {
|
||||||
|
std::memset(voxels.get(), 0xFF, sizeof(voxel) * w * h * d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition(int x, int y, int z) {
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
int getX() const {
|
int getX() const {
|
||||||
return x;
|
return x;
|
||||||
|
|
@ -40,11 +48,11 @@ public:
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
voxel* getVoxels() const {
|
voxel* getVoxels() {
|
||||||
return voxels.get();
|
return voxels.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
light_t* getLights() const {
|
light_t* getLights() {
|
||||||
return lights.get();
|
return lights.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,4 +80,83 @@ public:
|
||||||
}
|
}
|
||||||
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
int x, y, z;
|
||||||
|
int w, h, d;
|
||||||
|
std::unique_ptr<voxel[]> voxels;
|
||||||
|
std::unique_ptr<light_t[]> lights;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <int w, int h, int d>
|
||||||
|
class StaticVoxelsVolume {
|
||||||
|
public:
|
||||||
|
static inline constexpr size_t size = w * h * d;
|
||||||
|
static inline constexpr int width = w;
|
||||||
|
static inline constexpr int height = h;
|
||||||
|
static inline constexpr int depth = d;
|
||||||
|
|
||||||
|
StaticVoxelsVolume()
|
||||||
|
: StaticVoxelsVolume(0, 0, 0) {}
|
||||||
|
|
||||||
|
StaticVoxelsVolume(int x, int y, int z)
|
||||||
|
: x(x), y(y), z(z) {
|
||||||
|
std::memset(voxels, 0xFF, sizeof(voxel) * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition(int x, int y, int z) {
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getX() const {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getY() const {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getZ() const {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
voxel* getVoxels() {
|
||||||
|
return voxels;
|
||||||
|
}
|
||||||
|
|
||||||
|
light_t* getLights() {
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blockid_t pickBlockId(int bx, int by, int bz) const {
|
||||||
|
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
|
||||||
|
bz >= z + d) {
|
||||||
|
return BLOCK_VOID;
|
||||||
|
}
|
||||||
|
return voxels[vox_index(bx - x, by - y, bz - z, w, d)].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline voxel pickBlock(int bx, int by, int bz) const {
|
||||||
|
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
|
||||||
|
bz >= z + d) {
|
||||||
|
return {BLOCK_VOID, {}};
|
||||||
|
}
|
||||||
|
return voxels[vox_index(bx - x, by - y, bz - z, w, d)];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline light_t pickLight(int bx, int by, int bz) const {
|
||||||
|
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
|
||||||
|
bz >= z + d) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int x, y, z;
|
||||||
|
voxel voxels[size];
|
||||||
|
light_t lights[size];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ std::shared_ptr<Task> WorldConverter::startTask(
|
||||||
}
|
}
|
||||||
auto pool = std::make_shared<util::ThreadPool<ConvertTask, int>>(
|
auto pool = std::make_shared<util::ThreadPool<ConvertTask, int>>(
|
||||||
"converter-pool",
|
"converter-pool",
|
||||||
[=]() { return std::make_shared<ConverterWorker>(converter); },
|
[=]() { return std::make_unique<ConverterWorker>(converter); },
|
||||||
[=](int&&) {}
|
[=](int&&) {}
|
||||||
);
|
);
|
||||||
auto& converterTasks = converter->tasks;
|
auto& converterTasks = converter->tasks;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue