Начало отделение генерации мешей чанков в отдельном потоке
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "glm/ext/scalar_constants.hpp"
|
||||
#include "glm/matrix.hpp"
|
||||
#include "glm/trigonometric.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -17,13 +18,214 @@
|
||||
|
||||
namespace LV::Client::VK {
|
||||
|
||||
void VulkanRenderSession::ThreadVertexObj_t::run() {
|
||||
Logger LOG = "ThreadVertex";
|
||||
|
||||
// Контейнеры событий
|
||||
std::vector<DefVoxelId_t> changedDefines_Voxel;
|
||||
std::vector<DefNodeId_t> changedDefines_Node;
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> changedContent_Chunk;
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> changedContent_RegionRemove;
|
||||
|
||||
|
||||
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Voxels;
|
||||
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Nodes;
|
||||
|
||||
try {
|
||||
while(Stage != EnumStage::Shutdown) {
|
||||
if(Stage != EnumStage::WorldUpdate) {
|
||||
// Переносим все события в локальные хранилища
|
||||
ServerSession_InUse = true;
|
||||
|
||||
if(!ChangedContent_Chunk.empty()) {
|
||||
for(auto& [worldId, chunks] : ChangedContent_Chunk) {
|
||||
auto &list = changedContent_Chunk[worldId];
|
||||
list.insert(list.end(), chunks.begin(), chunks.end());
|
||||
}
|
||||
|
||||
ChangedContent_Chunk.clear();
|
||||
}
|
||||
|
||||
if(!ChangedContent_RegionRemove.empty()) {
|
||||
for(auto& [worldId, chunks] : ChangedContent_RegionRemove) {
|
||||
auto &list = changedContent_RegionRemove[worldId];
|
||||
list.insert(list.end(), chunks.begin(), chunks.end());
|
||||
}
|
||||
|
||||
ChangedContent_RegionRemove.clear();
|
||||
}
|
||||
|
||||
if(!ChangedDefines_Voxel.empty()) {
|
||||
changedDefines_Voxel.insert(changedDefines_Voxel.end(), ChangedDefines_Voxel.begin(), ChangedDefines_Voxel.end());
|
||||
ChangedDefines_Voxel.clear();
|
||||
|
||||
std::sort(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
||||
auto last = std::unique(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
||||
changedDefines_Voxel.erase(last, changedDefines_Voxel.end());
|
||||
}
|
||||
|
||||
if(!ChangedDefines_Node.empty()) {
|
||||
changedDefines_Node.insert(changedDefines_Node.end(), ChangedDefines_Node.begin(), ChangedDefines_Voxel.end());
|
||||
ChangedDefines_Node.clear();
|
||||
|
||||
std::sort(changedDefines_Node.begin(), changedDefines_Node.end());
|
||||
auto last = std::unique(changedDefines_Node.begin(), changedDefines_Node.end());
|
||||
changedDefines_Node.erase(last, changedDefines_Node.end());
|
||||
}
|
||||
|
||||
ServerSession_InUse = false;
|
||||
|
||||
// Ищем чанки, которые нужно перерисовать
|
||||
if(!changedDefines_Voxel.empty() || changedDefines_Node.empty()) {
|
||||
for(auto& [worldId, regions] : ChunkMesh) {
|
||||
for(auto& [regionPos, chunks] : regions) {
|
||||
for(size_t index = 0; index < chunks.size(); index++) {
|
||||
if(!changedDefines_Voxel.empty() && !chunks[index].VoxelDefines.empty()) {
|
||||
bool hasIntersection = false;
|
||||
{
|
||||
size_t i = 0, j = 0;
|
||||
while(i < changedDefines_Voxel.size() && j < chunks[index].VoxelDefines.size()) {
|
||||
if (changedDefines_Voxel[i] == chunks[index].VoxelDefines[j]) {
|
||||
hasIntersection = true;
|
||||
break;
|
||||
} else if (changedDefines_Voxel[i] < chunks[index].VoxelDefines[j])
|
||||
++i;
|
||||
else
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasIntersection) {
|
||||
changedContent_Chunk[worldId].push_back((Pos::GlobalChunk(regionPos) << 2) + Pos::GlobalChunk(Pos::bvec4u().unpack(index)));
|
||||
}
|
||||
}
|
||||
|
||||
if(!changedDefines_Node.empty() && !chunks[index].NodeDefines.empty()) {
|
||||
bool hasIntersection = false;
|
||||
{
|
||||
size_t i = 0, j = 0;
|
||||
while(i < changedDefines_Node.size() && j < chunks[index].NodeDefines.size()) {
|
||||
if (changedDefines_Node[i] == chunks[index].NodeDefines[j]) {
|
||||
hasIntersection = true;
|
||||
break;
|
||||
} else if (changedDefines_Node[i] < chunks[index].NodeDefines[j])
|
||||
++i;
|
||||
else
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasIntersection) {
|
||||
changedContent_Chunk[worldId].push_back((Pos::GlobalChunk(regionPos) << 2) + Pos::GlobalChunk(Pos::bvec4u().unpack(index)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changedDefines_Voxel.clear();
|
||||
changedDefines_Node.clear();
|
||||
|
||||
// Уникализируем
|
||||
for(auto& [worldId, chunks] : changedContent_Chunk) {
|
||||
std::sort(chunks.begin(), chunks.end());
|
||||
auto last = std::unique(chunks.begin(), chunks.end());
|
||||
chunks.erase(last, chunks.end());
|
||||
}
|
||||
|
||||
for(auto& [worldId, regions] : changedContent_RegionRemove) {
|
||||
std::sort(regions.begin(), regions.end());
|
||||
auto last = std::unique(regions.begin(), regions.end());
|
||||
regions.erase(last, regions.end());
|
||||
}
|
||||
}
|
||||
|
||||
if(Stage == EnumStage::ComposingCommandBuffer || Stage == EnumStage::Render) {
|
||||
// Здесь можно обработать события, и подготовить меши по данным с мира
|
||||
// changedContent_Chunk
|
||||
|
||||
ServerSession_InUse = true;
|
||||
|
||||
std::vector<WorldId_t> toRemove;
|
||||
for(auto& [worldId, chunks] : changedContent_Chunk) {
|
||||
if(Stage != EnumStage::ComposingCommandBuffer && Stage != EnumStage::Render)
|
||||
break;
|
||||
|
||||
while(!chunks.empty() && Stage != EnumStage::ComposingCommandBuffer && Stage != EnumStage::Render) {
|
||||
|
||||
// TODO: Сгенерировать меши
|
||||
|
||||
chunks.pop_back();
|
||||
}
|
||||
|
||||
if(chunks.empty())
|
||||
toRemove.push_back(worldId);
|
||||
}
|
||||
|
||||
for(WorldId_t worldId : toRemove)
|
||||
changedContent_Chunk.erase(changedContent_Chunk.find(worldId));
|
||||
|
||||
ServerSession_InUse = false;
|
||||
}
|
||||
|
||||
if(Stage == EnumStage::Render || Stage == EnumStage::WorldUpdate) {
|
||||
// Здесь можно выгрузить готовые данные в ChunkMesh
|
||||
ChunkMesh_IsUse = true;
|
||||
|
||||
// Удаляем регионы
|
||||
for(auto& [worldId, regions] : changedContent_RegionRemove) {
|
||||
auto iterWorld = ChunkMesh.find(worldId);
|
||||
if(iterWorld == ChunkMesh.end())
|
||||
continue;
|
||||
|
||||
for(Pos::GlobalRegion regionPos : regions) {
|
||||
auto iterRegion = iterWorld->second.find(regionPos);
|
||||
if(iterRegion == iterWorld->second.end())
|
||||
continue;
|
||||
|
||||
for(size_t index = 0; index < iterRegion->second.size(); index++) {
|
||||
auto &chunk = iterRegion->second[index];
|
||||
chunk.NodeDefines.clear();
|
||||
chunk.VoxelDefines.clear();
|
||||
|
||||
VertexPool_Voxels.dropVertexs(chunk.VoxelPointer);
|
||||
VertexPool_Nodes.dropVertexs(chunk.NodePointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем обновлённые меши
|
||||
|
||||
ChunkMesh_IsUse = false;
|
||||
}
|
||||
}
|
||||
} catch(const std::exception &exc) {
|
||||
LOG.error() << exc.what();
|
||||
}
|
||||
|
||||
ChunkMesh_IsUse = false;
|
||||
ServerSession_InUse = false;
|
||||
}
|
||||
|
||||
void VulkanRenderSession::VulkanContext::onUpdate() {
|
||||
// {
|
||||
// Сделать отдельный пул комманд?
|
||||
// auto lock = ThreadVertexObj.lock();
|
||||
// lock->VertexPool_Voxels.update(VkInst->Graphics.Pool);
|
||||
// lock->VertexPool_Nodes.update(VkInst->Graphics.Pool);
|
||||
// }
|
||||
|
||||
MainTest.atlasUpdateDynamicData();
|
||||
LightDummy.atlasUpdateDynamicData();
|
||||
}
|
||||
|
||||
VulkanRenderSession::VulkanRenderSession()
|
||||
{
|
||||
}
|
||||
|
||||
VulkanRenderSession::~VulkanRenderSession() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void VulkanRenderSession::free(Vulkan *instance) {
|
||||
@@ -674,57 +876,37 @@ void VulkanRenderSession::onContentDefinesLost(std::unordered_map<EnumDefContent
|
||||
}
|
||||
|
||||
void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered_set<Pos::GlobalChunk>& changeOrAddList, const std::unordered_set<Pos::GlobalRegion>& remove) {
|
||||
auto &table = External.ChunkVoxelMesh[worldId];
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> chunkChanges;
|
||||
chunkChanges[worldId] = std::vector<Pos::GlobalChunk>(changeOrAddList.begin(), changeOrAddList.end());
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> regionRemove;
|
||||
regionRemove[worldId] = std::vector<Pos::GlobalRegion>(remove.begin(), remove.end());
|
||||
VKCTX->ThreadVertexObj.onContentChunkChange(chunkChanges, regionRemove);
|
||||
|
||||
// if(chunk.Voxels.empty()) {
|
||||
// VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(buffers));
|
||||
// } else {
|
||||
// std::vector<VoxelVertexPoint> vertexs = generateMeshForVoxelChunks(chunk.Voxels);
|
||||
// auto &voxels = std::get<0>(buffers);
|
||||
// VKCTX->VertexPool_Voxels.relocate(voxels, std::move(vertexs));
|
||||
// }
|
||||
|
||||
for(Pos::GlobalChunk pos : changeOrAddList) {
|
||||
Pos::GlobalRegion rPos = pos >> 2;
|
||||
Pos::bvec4u cPos = pos & 0x3;
|
||||
// std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes.data());
|
||||
|
||||
auto &buffers = table[pos];
|
||||
|
||||
const auto &chunk = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos.pack()];
|
||||
|
||||
if(chunk.Voxels.empty()) {
|
||||
VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(buffers));
|
||||
} else {
|
||||
std::vector<VoxelVertexPoint> vertexs = generateMeshForVoxelChunks(chunk.Voxels);
|
||||
auto &voxels = std::get<0>(buffers);
|
||||
VKCTX->VertexPool_Voxels.relocate(voxels, std::move(vertexs));
|
||||
}
|
||||
|
||||
std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes.data());
|
||||
|
||||
if(vertexs2.empty()) {
|
||||
VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(buffers));
|
||||
} else {
|
||||
auto &nodes = std::get<1>(buffers);
|
||||
VKCTX->VertexPool_Nodes.relocate(nodes, std::move(vertexs2));
|
||||
}
|
||||
// if(vertexs2.empty()) {
|
||||
// VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(buffers));
|
||||
// } else {
|
||||
// auto &nodes = std::get<1>(buffers);
|
||||
// VKCTX->VertexPool_Nodes.relocate(nodes, std::move(vertexs2));
|
||||
// }
|
||||
|
||||
if(!std::get<0>(buffers) && !std::get<1>(buffers)) {
|
||||
auto iter = table.find(pos);
|
||||
if(iter != table.end())
|
||||
table.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
for(Pos::GlobalRegion pos : remove) {
|
||||
for(int z = 0; z < 4; z++)
|
||||
for(int y = 0; y < 4; y++)
|
||||
for(int x = 0; x < 4; x++) {
|
||||
auto iter = table.find((Pos::GlobalChunk(pos) << 2) + Pos::GlobalChunk(x, y, z));
|
||||
if(iter != table.end()) {
|
||||
VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(iter->second));
|
||||
VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(iter->second));
|
||||
table.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(table.empty())
|
||||
External.ChunkVoxelMesh.erase( External.ChunkVoxelMesh.find(worldId));
|
||||
// if(!std::get<0>(buffers) && !std::get<1>(buffers)) {
|
||||
// auto iter = table.find(pos);
|
||||
// if(iter != table.end())
|
||||
// table.erase(iter);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
void VulkanRenderSession::setCameraPos(WorldId_t worldId, Pos::Object pos, glm::quat quat) {
|
||||
WorldId = worldId;
|
||||
Pos = pos;
|
||||
@@ -733,10 +915,7 @@ void VulkanRenderSession::setCameraPos(WorldId_t worldId, Pos::Object pos, glm::
|
||||
|
||||
void VulkanRenderSession::beforeDraw() {
|
||||
if(VKCTX) {
|
||||
VKCTX->MainTest.atlasUpdateDynamicData();
|
||||
VKCTX->LightDummy.atlasUpdateDynamicData();
|
||||
VKCTX->VertexPool_Voxels.update(VkInst->Graphics.Pool);
|
||||
VKCTX->VertexPool_Nodes.update(VkInst->Graphics.Pool);
|
||||
VKCTX->onUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,25 +1074,25 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
|
||||
{
|
||||
Pos::GlobalChunk x64offset = X64Offset >> Pos::Object_t::BS_Bit >> 4;
|
||||
|
||||
auto iterWorld = External.ChunkVoxelMesh.find(WorldId);
|
||||
if(iterWorld != External.ChunkVoxelMesh.end()) {
|
||||
glm::mat4 orig = PCO.Model;
|
||||
// auto iterWorld = External.ChunkVoxelMesh.find(WorldId);
|
||||
// if(iterWorld != External.ChunkVoxelMesh.end()) {
|
||||
// glm::mat4 orig = PCO.Model;
|
||||
|
||||
for(auto &pair : iterWorld->second) {
|
||||
if(auto& nodes = std::get<1>(pair.second)) {
|
||||
glm::vec3 cpos(pair.first-x64offset);
|
||||
PCO.Model = glm::translate(orig, cpos*16.f);
|
||||
auto [vkBuffer, offset] = VKCTX->VertexPool_Nodes.map(nodes);
|
||||
// for(auto &pair : iterWorld->second) {
|
||||
// if(auto& nodes = std::get<1>(pair.second)) {
|
||||
// glm::vec3 cpos(pair.first-x64offset);
|
||||
// PCO.Model = glm::translate(orig, cpos*16.f);
|
||||
// auto [vkBuffer, offset] = VKCTX->VertexPool_Nodes.map(nodes);
|
||||
|
||||
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
||||
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
||||
vkCmdDraw(drawCmd, nodes.VertexCount, 1, offset, 0);
|
||||
}
|
||||
}
|
||||
// vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
||||
// VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
||||
// vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
||||
// vkCmdDraw(drawCmd, nodes.VertexCount, 1, offset, 0);
|
||||
// }
|
||||
// }
|
||||
|
||||
PCO.Model = orig;
|
||||
}
|
||||
// PCO.Model = orig;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
#include <Client/Vulkan/Vulkan.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include "Abstract.hpp"
|
||||
#include "TOSLib.hpp"
|
||||
#include "VertexPool.hpp"
|
||||
|
||||
/*
|
||||
@@ -39,7 +43,9 @@ struct WorldPCO {
|
||||
|
||||
static_assert(sizeof(WorldPCO) == 128);
|
||||
|
||||
|
||||
/*
|
||||
Модуль, рисующий то, что предоставляет IServerSession
|
||||
*/
|
||||
class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
||||
VK::Vulkan *VkInst = nullptr;
|
||||
// Доступ к миру на стороне клиента
|
||||
@@ -63,21 +69,131 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
||||
glm::vec3 X64Offset_f, X64Delta; // Смещение мира относительно игрока в матрице вида (0 -> 64)
|
||||
glm::quat Quat;
|
||||
|
||||
/*
|
||||
Поток, занимающийся генерацией меша на основе нод и вокселей
|
||||
Требует доступ к профилям в ServerSession (ServerSession должен быть заблокирован только на чтение)
|
||||
Также доступ к идентификаторам текстур в VulkanRenderSession (только на чтение)
|
||||
Должен оповещаться об изменениях профилей и событий чанков
|
||||
Удалённые мешы хранятся в памяти N количество кадров
|
||||
*/
|
||||
struct ThreadVertexObj_t {
|
||||
|
||||
// Здесь не хватает стадии работы с текстурами
|
||||
enum class EnumStage {
|
||||
// Постройка буфера команд на рисовку
|
||||
// В этот период не должно быть изменений в таблице,
|
||||
// хранящей указатели на данные для рендера ChunkMesh
|
||||
// Можно работать с миром
|
||||
// Здесь нужно дождаться завершения работы с ChunkMesh
|
||||
ComposingCommandBuffer,
|
||||
// В этот период можно менять ChunkMesh
|
||||
// Можно работать с миром
|
||||
Render,
|
||||
// В этот период нельзя работать с миром
|
||||
// Можно менять ChunkMesh
|
||||
// Здесь нужно дождаться завершения работы с миром, только в
|
||||
// этом этапе могут приходить события изменения чанков и определений
|
||||
WorldUpdate,
|
||||
|
||||
Shutdown
|
||||
} Stage = EnumStage::Render;
|
||||
|
||||
volatile bool ChunkMesh_IsUse = false, ServerSession_InUse = false;
|
||||
|
||||
struct ChunkObj_t {
|
||||
// Сортированный список уникальных значений
|
||||
std::vector<DefVoxelId_t> VoxelDefines;
|
||||
VertexPool<VoxelVertexPoint>::Pointer VoxelPointer;
|
||||
std::vector<DefNodeId_t> NodeDefines;
|
||||
VertexPool<NodeVertexStatic>::Pointer NodePointer;
|
||||
};
|
||||
|
||||
std::unordered_map<WorldId_t,
|
||||
std::unordered_map<Pos::GlobalRegion, std::array<ChunkObj_t, 4*4*4>>
|
||||
> ChunkMesh;
|
||||
|
||||
ThreadVertexObj_t(Vulkan* vkInst)
|
||||
: VertexPool_Voxels(vkInst),
|
||||
VertexPool_Nodes(vkInst),
|
||||
Thread(&ThreadVertexObj_t::run, this)
|
||||
{}
|
||||
|
||||
~ThreadVertexObj_t() {
|
||||
Stage = EnumStage::Shutdown;
|
||||
Thread.join();
|
||||
}
|
||||
|
||||
// Сюда входят добавленные/изменённые/удалённые определения нод и вокселей
|
||||
// Чтобы перерисовать чанки, связанные с ними
|
||||
void onContentDefinesChange(const std::vector<DefVoxelId_t>& voxels, const std::vector<DefNodeId_t>& nodes) {
|
||||
ChangedDefines_Voxel.insert(ChangedDefines_Voxel.end(), voxels.begin(), voxels.end());
|
||||
ChangedDefines_Node.insert(ChangedDefines_Node.end(), nodes.begin(), nodes.end());
|
||||
}
|
||||
|
||||
// Изменение/удаление чанков
|
||||
void onContentChunkChange(const std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>>& chunkChanges, const std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>>& regionRemove) {
|
||||
for(auto& [worldId, chunks] : chunkChanges) {
|
||||
auto &list = ChangedContent_Chunk[worldId];
|
||||
list.insert(list.end(), chunks.begin(), chunks.end());
|
||||
}
|
||||
|
||||
for(auto& [worldId, regions] : regionRemove) {
|
||||
auto &list = ChangedContent_RegionRemove[worldId];
|
||||
list.insert(list.end(), regions.begin(), regions.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Синхронизация потока рендера мира
|
||||
void pushStage(EnumStage stage) {
|
||||
if(Stage == EnumStage::Shutdown)
|
||||
MAKE_ERROR("Остановка из-за ошибки ThreadVertex");
|
||||
|
||||
assert(Stage != stage);
|
||||
|
||||
Stage = stage;
|
||||
if(stage == EnumStage::ComposingCommandBuffer) {
|
||||
while(ChunkMesh_IsUse);
|
||||
} else if(stage == EnumStage::WorldUpdate) {
|
||||
while(ServerSession_InUse);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Буферы для хранения вершин
|
||||
VertexPool<VoxelVertexPoint> VertexPool_Voxels;
|
||||
VertexPool<NodeVertexStatic> VertexPool_Nodes;
|
||||
// Списки изменённых определений
|
||||
std::vector<DefVoxelId_t> ChangedDefines_Voxel;
|
||||
std::vector<DefNodeId_t> ChangedDefines_Node;
|
||||
// Список чанков на перерисовку
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> ChangedContent_Chunk;
|
||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> ChangedContent_RegionRemove;
|
||||
// Внешний поток
|
||||
std::thread Thread;
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
struct VulkanContext {
|
||||
VK::Vulkan *VkInst;
|
||||
AtlasImage MainTest, LightDummy;
|
||||
Buffer TestQuad;
|
||||
std::optional<Buffer> TestVoxel;
|
||||
|
||||
ThreadVertexObj_t ThreadVertexObj;
|
||||
|
||||
VertexPool<VoxelVertexPoint> VertexPool_Voxels;
|
||||
VertexPool<NodeVertexStatic> VertexPool_Nodes;
|
||||
|
||||
VulkanContext(Vulkan *vkInst)
|
||||
: MainTest(vkInst), LightDummy(vkInst),
|
||||
VulkanContext(Vulkan* vkInst)
|
||||
: VkInst(vkInst),
|
||||
MainTest(vkInst), LightDummy(vkInst),
|
||||
TestQuad(vkInst, sizeof(NodeVertexStatic)*6*3*2),
|
||||
VertexPool_Voxels(vkInst),
|
||||
VertexPool_Nodes(vkInst)
|
||||
ThreadVertexObj(vkInst)
|
||||
{}
|
||||
|
||||
~VulkanContext() {
|
||||
ThreadVertexObj.pushStage(ThreadVertexObj_t::EnumStage::Shutdown);
|
||||
}
|
||||
|
||||
void onUpdate();
|
||||
};
|
||||
|
||||
std::shared_ptr<VulkanContext> VKCTX;
|
||||
@@ -119,11 +235,6 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
||||
std::map<BinTextureId_t, uint16_t> ServerToAtlas;
|
||||
|
||||
struct {
|
||||
std::unordered_map<WorldId_t,
|
||||
std::unordered_map<Pos::GlobalChunk,
|
||||
std::pair<VertexPool<VoxelVertexPoint>::Pointer, VertexPool<NodeVertexStatic>::Pointer> // Voxels, Nodes
|
||||
>
|
||||
> ChunkVoxelMesh;
|
||||
} External;
|
||||
|
||||
virtual void free(Vulkan *instance) override;
|
||||
|
||||
@@ -97,12 +97,14 @@ public:
|
||||
return out;
|
||||
}
|
||||
|
||||
void unpack(const Pack pack) requires (N*BitsPerComponent <= 64) {
|
||||
BitVec3 unpack(const Pack pack) requires (N*BitsPerComponent <= 64) {
|
||||
using U = std::make_unsigned_t<T>;
|
||||
|
||||
for(size_t iter = 0; iter < N; iter++) {
|
||||
set(iter, T(U((pack >> BitsPerComponent*iter) & U((Pack(1) << BitsPerComponent)-1))));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator<=>(const BitVec3&) const = default;
|
||||
|
||||
Reference in New Issue
Block a user