summaryrefslogtreecommitdiffstats
path: root/game/client/world/chunk_mesher.cc
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/world/chunk_mesher.cc')
-rw-r--r--game/client/world/chunk_mesher.cc450
1 files changed, 0 insertions, 450 deletions
diff --git a/game/client/world/chunk_mesher.cc b/game/client/world/chunk_mesher.cc
deleted file mode 100644
index da90d2e..0000000
--- a/game/client/world/chunk_mesher.cc
+++ /dev/null
@@ -1,450 +0,0 @@
-#include "client/pch.hh"
-
-#include "client/world/chunk_mesher.hh"
-
-#include "core/math/crc64.hh"
-
-#include "core/threading.hh"
-
-#include "shared/world/chunk.hh"
-#include "shared/world/dimension.hh"
-#include "shared/world/voxel.hh"
-#include "shared/world/voxel_registry.hh"
-
-#include "shared/coord.hh"
-
-#include "client/world/chunk_quad.hh"
-#include "client/world/voxel_atlas.hh"
-
-#include "client/globals.hh"
-#include "client/session.hh"
-
-using QuadBuilder = std::vector<world::ChunkQuad>;
-
-using CachedChunkCoord = unsigned short;
-constexpr static CachedChunkCoord CPOS_ITSELF = 0x0000;
-constexpr static CachedChunkCoord CPOS_NORTH = 0x0001;
-constexpr static CachedChunkCoord CPOS_SOUTH = 0x0002;
-constexpr static CachedChunkCoord CPOS_EAST = 0x0003;
-constexpr static CachedChunkCoord CPOS_WEST = 0x0004;
-constexpr static CachedChunkCoord CPOS_TOP = 0x0005;
-constexpr static CachedChunkCoord CPOS_BOTTOM = 0x0006;
-constexpr static const size_t NUM_CACHED_CPOS = 7;
-
-static const CachedChunkCoord get_cached_cpos(const chunk_pos& pivot, const chunk_pos& cpos)
-{
- static const CachedChunkCoord nx[3] = { CPOS_WEST, 0, CPOS_EAST };
- static const CachedChunkCoord ny[3] = { CPOS_BOTTOM, 0, CPOS_TOP };
- static const CachedChunkCoord nz[3] = { CPOS_NORTH, 0, CPOS_SOUTH };
-
- if(pivot != cpos) {
- chunk_pos delta = pivot - cpos;
- delta[0] = glm::clamp<std::int64_t>(delta[0], -1, 1);
- delta[1] = glm::clamp<std::int64_t>(delta[1], -1, 1);
- delta[2] = glm::clamp<std::int64_t>(delta[2], -1, 1);
-
- if(delta[0]) {
- return nx[delta[0] + 1];
- }
- else if(delta[1]) {
- return ny[delta[1] + 1];
- }
- else {
- return nz[delta[2] + 1];
- }
- }
-
- return CPOS_ITSELF;
-}
-
-class GL_MeshingTask final : public Task {
-public:
- explicit GL_MeshingTask(entt::entity entity, const chunk_pos& cpos);
- virtual ~GL_MeshingTask(void) = default;
- virtual void process(void) override;
- virtual void finalize(void) override;
-
-private:
- bool vis_test(const world::Voxel* voxel, const local_pos& lpos) const;
- void push_quad_a(const world::Voxel* voxel, const glm::fvec3& pos, const glm::fvec2& size, world::VoxelFace face);
- void push_quad_v(const world::Voxel* voxel, const glm::fvec3& pos, const glm::fvec2& size, world::VoxelFace face, std::size_t entropy);
- void make_cube(const world::Voxel* voxel, const local_pos& lpos, world::VoxelVisBits vis, std::size_t entropy);
- void cache_chunk(const chunk_pos& cpos);
-
-private:
- std::array<world::VoxelStorage, NUM_CACHED_CPOS> m_cache;
- std::vector<QuadBuilder> m_quads_b; // blending
- std::vector<QuadBuilder> m_quads_s; // solid
- entt::entity m_entity;
- chunk_pos m_cpos;
-};
-
-GL_MeshingTask::GL_MeshingTask(entt::entity entity, const chunk_pos& cpos)
-{
- m_entity = entity;
- m_cpos = cpos;
-
- cache_chunk(m_cpos);
- cache_chunk(m_cpos + DIR_NORTH<chunk_pos::value_type>);
- cache_chunk(m_cpos + DIR_SOUTH<chunk_pos::value_type>);
- cache_chunk(m_cpos + DIR_EAST<chunk_pos::value_type>);
- cache_chunk(m_cpos + DIR_WEST<chunk_pos::value_type>);
- cache_chunk(m_cpos + DIR_DOWN<chunk_pos::value_type>);
- cache_chunk(m_cpos + DIR_UP<chunk_pos::value_type>);
-}
-
-void GL_MeshingTask::process(void)
-{
- m_quads_b.resize(world::voxel_atlas::plane_count());
- m_quads_s.resize(world::voxel_atlas::plane_count());
-
- const auto& voxels = m_cache.at(CPOS_ITSELF);
-
- for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) {
- if(m_status == task_status::CANCELLED) {
- m_quads_b.clear();
- m_quads_s.clear();
- return;
- }
-
- const auto lpos = coord::to_local(i);
- const auto voxel = world::voxel_registry::find(voxels[i]);
-
- if(voxel == nullptr) {
- // Either a NULL_VOXEL_ID or something went
- // horribly wrong and we don't what this is
- continue;
- }
-
- unsigned int vis = 0U;
-
- if(vis_test(voxel, lpos + DIR_NORTH<local_pos::value_type>)) {
- vis |= world::VVIS_NORTH;
- }
-
- if(vis_test(voxel, lpos + DIR_SOUTH<local_pos::value_type>)) {
- vis |= world::VVIS_SOUTH;
- }
-
- if(vis_test(voxel, lpos + DIR_EAST<local_pos::value_type>)) {
- vis |= world::VVIS_EAST;
- }
-
- if(vis_test(voxel, lpos + DIR_WEST<local_pos::value_type>)) {
- vis |= world::VVIS_WEST;
- }
-
- if(vis_test(voxel, lpos + DIR_UP<local_pos::value_type>)) {
- vis |= world::VVIS_UP;
- }
-
- if(vis_test(voxel, lpos + DIR_DOWN<local_pos::value_type>)) {
- vis |= world::VVIS_DOWN;
- }
-
- const auto vpos = coord::to_voxel(m_cpos, lpos);
- const auto entropy_src = vpos[0] * vpos[1] * vpos[2];
- const auto entropy = math::crc64(&entropy_src, sizeof(entropy_src));
-
- // FIXME: handle different voxel types
- make_cube(voxel, lpos, world::VoxelVisBits(vis), entropy);
- }
-}
-
-void GL_MeshingTask::finalize(void)
-{
- if(!globals::dimension || !globals::dimension->chunks.valid(m_entity)) {
- // We either disconnected or something
- // else happened that invalidated the entity
- return;
- }
-
- auto& component = globals::dimension->chunks.emplace_or_replace<world::ChunkMesh>(m_entity);
-
- const std::size_t plane_count_nb = m_quads_s.size();
- const std::size_t plane_count_b = m_quads_b.size();
-
- bool has_no_submeshes_b = true;
- bool has_no_submeshes_nb = true;
-
- component.quad_nb.resize(plane_count_nb);
- component.quad_b.resize(plane_count_b);
-
- for(std::size_t plane = 0; plane < plane_count_nb; ++plane) {
- auto& builder = m_quads_s[plane];
- auto& buffer = component.quad_nb[plane];
-
- if(builder.empty()) {
- if(buffer.handle) {
- glDeleteBuffers(1, &buffer.handle);
- buffer.handle = 0;
- buffer.size = 0;
- }
- }
- else {
- if(!buffer.handle) {
- glGenBuffers(1, &buffer.handle);
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, buffer.handle);
- glBufferData(GL_ARRAY_BUFFER, sizeof(world::ChunkQuad) * builder.size(), builder.data(), GL_STATIC_DRAW);
- buffer.size = builder.size();
- has_no_submeshes_nb = false;
- }
- }
-
- for(std::size_t plane = 0; plane < plane_count_b; ++plane) {
- auto& builder = m_quads_b[plane];
- auto& buffer = component.quad_b[plane];
-
- if(builder.empty()) {
- if(buffer.handle) {
- glDeleteBuffers(1, &buffer.handle);
- buffer.handle = 0;
- buffer.size = 0;
- }
- }
- else {
- if(!buffer.handle) {
- glGenBuffers(1, &buffer.handle);
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, buffer.handle);
- glBufferData(GL_ARRAY_BUFFER, sizeof(world::ChunkQuad) * builder.size(), builder.data(), GL_STATIC_DRAW);
- buffer.size = builder.size();
- has_no_submeshes_b = false;
- }
- }
-
- if(has_no_submeshes_b && has_no_submeshes_nb) {
- globals::dimension->chunks.remove<world::ChunkMesh>(m_entity);
- }
-}
-
-bool GL_MeshingTask::vis_test(const world::Voxel* voxel, const local_pos& lpos) const
-{
- const auto pvpos = coord::to_voxel(m_cpos, lpos);
- const auto pcpos = coord::to_chunk(pvpos);
- const auto plpos = coord::to_local(pvpos);
- const auto index = coord::to_index(plpos);
-
- const auto cached_cpos = get_cached_cpos(m_cpos, pcpos);
- const auto& voxels = m_cache.at(cached_cpos);
- const auto neighbour = world::voxel_registry::find(voxels[index]);
-
- bool result;
-
- if(neighbour == nullptr) {
- result = true;
- }
- else if(neighbour == voxel) {
- result = false;
- }
- else if(neighbour->get_render_mode() != voxel->get_render_mode()) {
- result = true;
- }
- else {
- result = false;
- }
-
- return result;
-}
-
-void GL_MeshingTask::push_quad_a(const world::Voxel* voxel, const glm::fvec3& pos, const glm::fvec2& size, world::VoxelFace face)
-{
- auto cached_offset = voxel->get_cached_face_offset(face);
- auto cached_plane = voxel->get_cached_face_plane(face);
- auto& textures = voxel->get_face_textures(face);
-
- switch(voxel->get_render_mode()) {
- case world::VRENDER_OPAQUE:
- m_quads_s[cached_plane].push_back(make_chunk_quad(pos, size, face, cached_offset, textures.size()));
- break;
-
- case world::VRENDER_BLEND:
- m_quads_b[cached_plane].push_back(make_chunk_quad(pos, size, face, cached_offset, textures.size()));
- break;
- }
-}
-
-void GL_MeshingTask::push_quad_v(const world::Voxel* voxel, const glm::fvec3& pos, const glm::fvec2& size, world::VoxelFace face,
- std::size_t entropy)
-{
- auto cached_offset = voxel->get_cached_face_offset(face);
- auto cached_plane = voxel->get_cached_face_plane(face);
- auto& textures = voxel->get_face_textures(face);
- auto index = entropy % textures.size();
-
- switch(voxel->get_render_mode()) {
- case world::VRENDER_OPAQUE:
- m_quads_s[cached_plane].push_back(make_chunk_quad(pos, size, face, cached_offset + index, 0));
- break;
-
- case world::VRENDER_BLEND:
- m_quads_b[cached_plane].push_back(make_chunk_quad(pos, size, face, cached_offset + index, 0));
- break;
- }
-}
-
-void GL_MeshingTask::make_cube(const world::Voxel* voxel, const local_pos& lpos, world::VoxelVisBits vis, std::size_t entropy)
-{
- const glm::fvec3 fpos = glm::fvec3(lpos);
- const glm::fvec2 fsize = glm::fvec2(1.0f, 1.0f);
-
- if(voxel->is_animated()) {
- if(vis & world::VVIS_NORTH) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_NORTH);
- }
-
- if(vis & world::VVIS_SOUTH) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_SOUTH);
- }
-
- if(vis & world::VVIS_EAST) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_EAST);
- }
-
- if(vis & world::VVIS_WEST) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_WEST);
- }
-
- if(vis & world::VVIS_UP) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_TOP);
- }
-
- if(vis & world::VVIS_DOWN) {
- push_quad_a(voxel, fpos, fsize, world::VFACE_BOTTOM);
- }
- }
- else {
- if(vis & world::VVIS_NORTH) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_NORTH, entropy);
- }
-
- if(vis & world::VVIS_SOUTH) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_SOUTH, entropy);
- }
-
- if(vis & world::VVIS_EAST) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_EAST, entropy);
- }
-
- if(vis & world::VVIS_WEST) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_WEST, entropy);
- }
-
- if(vis & world::VVIS_UP) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_TOP, entropy);
- }
-
- if(vis & world::VVIS_DOWN) {
- push_quad_v(voxel, fpos, fsize, world::VFACE_BOTTOM, entropy);
- }
- }
-}
-
-void GL_MeshingTask::cache_chunk(const chunk_pos& cpos)
-{
- const auto index = get_cached_cpos(m_cpos, cpos);
-
- if(const auto chunk = globals::dimension->find_chunk(cpos)) {
- m_cache[index] = chunk->get_voxels();
- return;
- }
-}
-
-// Bogus internal flag component
-struct NeedsMeshingComponent final {};
-
-static void on_chunk_create(const world::ChunkCreateEvent& event)
-{
- const std::array<chunk_pos, 6> neighbours = {
- event.cpos + DIR_NORTH<chunk_pos::value_type>,
- event.cpos + DIR_SOUTH<chunk_pos::value_type>,
- event.cpos + DIR_EAST<chunk_pos::value_type>,
- event.cpos + DIR_WEST<chunk_pos::value_type>,
- event.cpos + DIR_UP<chunk_pos::value_type>,
- event.cpos + DIR_DOWN<chunk_pos::value_type>,
- };
-
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity());
-
- for(const chunk_pos& cpos : neighbours) {
- if(const world::Chunk* chunk = globals::dimension->find_chunk(cpos)) {
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity());
- continue;
- }
- }
-}
-
-static void on_chunk_update(const world::ChunkUpdateEvent& event)
-{
- const std::array<chunk_pos, 6> neighbours = {
- event.cpos + DIR_NORTH<chunk_pos::value_type>,
- event.cpos + DIR_SOUTH<chunk_pos::value_type>,
- event.cpos + DIR_EAST<chunk_pos::value_type>,
- event.cpos + DIR_WEST<chunk_pos::value_type>,
- event.cpos + DIR_UP<chunk_pos::value_type>,
- event.cpos + DIR_DOWN<chunk_pos::value_type>,
- };
-
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity());
-
- for(const chunk_pos& cpos : neighbours) {
- if(const world::Chunk* chunk = globals::dimension->find_chunk(cpos)) {
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity());
- continue;
- }
- }
-}
-
-static void on_voxel_set(const world::VoxelSetEvent& event)
-{
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity());
-
- std::vector<chunk_pos> neighbours;
-
- for(int dim = 0; dim < 3; dim += 1) {
- chunk_pos offset = chunk_pos(0, 0, 0);
- offset[dim] = 1;
-
- if(event.lpos[dim] == 0) {
- neighbours.push_back(event.cpos - offset);
- continue;
- }
-
- if(event.lpos[dim] == (CHUNK_SIZE - 1)) {
- neighbours.push_back(event.cpos + offset);
- continue;
- }
- }
-
- for(const chunk_pos& cpos : neighbours) {
- if(const world::Chunk* chunk = globals::dimension->find_chunk(cpos)) {
- globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity());
- continue;
- }
- }
-}
-
-void world::chunk_mesher::init(void)
-{
- globals::dispatcher.sink<ChunkCreateEvent>().connect<&on_chunk_create>();
- globals::dispatcher.sink<ChunkUpdateEvent>().connect<&on_chunk_update>();
- globals::dispatcher.sink<VoxelSetEvent>().connect<&on_voxel_set>();
-}
-
-void world::chunk_mesher::shutdown(void)
-{
-}
-
-void world::chunk_mesher::update(void)
-{
- if(session::is_ingame()) {
- const auto group = globals::dimension->chunks.group<NeedsMeshingComponent>(entt::get<ChunkComponent>);
- for(const auto [entity, chunk] : group.each()) {
- globals::dimension->chunks.remove<NeedsMeshingComponent>(entity);
- threading::submit<GL_MeshingTask>(entity, chunk.cpos);
- }
- }
-}