diff options
-rw-r--r-- | draw/anim.cpp | 116 | ||||
-rw-r--r-- | draw/anim.hpp | 8 | ||||
-rw-r--r-- | src/chunk-scenery.cpp | 50 | ||||
-rw-r--r-- | src/chunk-scenery.hpp | 2 | ||||
-rw-r--r-- | src/chunk.hpp | 2 |
5 files changed, 105 insertions, 73 deletions
diff --git a/draw/anim.cpp b/draw/anim.cpp index f8a2835f..c6c12a64 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -6,7 +6,6 @@ #include "chunk-scenery.hpp" #include <cstdio> #include <Corrade/Containers/Optional.h> -#include <Corrade/Containers/ArrayView.h> #include <Magnum/GL/MeshView.h> #include <Magnum/GL/Texture.h> @@ -14,29 +13,10 @@ namespace floormat { anim_mesh::anim_mesh() { - _mesh.setCount(quad_index_count) + _mesh.setCount(6) .addVertexBuffer(_vertex_buffer, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) .setIndexBuffer(_index_buffer, 0, GL::MeshIndexType::UnsignedShort); CORRADE_INTERNAL_ASSERT(_mesh.isIndexed()); - - _batch_mesh.setCount(batch_size * quad_index_count) - .addVertexBuffer(_batch_vertex_buffer, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) - .setIndexBuffer(_index_buffer, 0, GL::MeshIndexType::UnsignedShort); - CORRADE_INTERNAL_ASSERT(_batch_mesh.isIndexed()); -} - -auto anim_mesh::make_batch_index_array() -> std::array<std::array<UnsignedShort, quad_index_count>, batch_size> -{ - std::array<std::array<UnsignedShort, quad_index_count>, batch_size> array; // NOLINT(cppcoreguidelines-pro-type-member-init) - for (std::size_t N = 0; N < batch_size; N++) - { - using u16 = uint16_t; - array[N] = { /* 3--1 1 */ - (u16)(0+N*4), (u16)(1+N*4), (u16)(2+N*4), /* | / /| */ - (u16)(2+N*4), (u16)(1+N*4), (u16)(3+N*4), /* |/ / | */ - }; /* 2 2--0 */ - } - return array; } std::array<UnsignedShort, 6> anim_mesh::make_index_array() @@ -77,59 +57,67 @@ void anim_mesh::add_clickable(tile_shader& shader, const Vector2i& win_size, void anim_mesh::draw(tile_shader& shader, const Vector2i& win_size, chunk& c, std::vector<clickable>& list) { - GL::MeshView mesh{_batch_mesh}; - auto [es] = c.ensure_scenery_mesh(_draw_array); - std::array<quad_data, batch_size> array = {}; - std::array<anim_atlas*, batch_size> atlases = {}; - anim_atlas* last_atlas = nullptr; - - constexpr auto do_draw = [](tile_shader& shader, GL::MeshView& mesh, anim_atlas*& last_atlas, anim_atlas* atlas, uint32_t i) { - constexpr auto max_index = uint32_t(batch_size*quad_index_count - 1); - if (atlas != last_atlas) - { - last_atlas = atlas; - atlas->texture().bind(0); - } - mesh.setCount((int)(quad_index_count)); - mesh.setIndexRange((int)(i*quad_index_count), 0, max_index); - shader.draw(mesh); - }; - - uint32_t k = 0; + constexpr auto quad_index_count = 6; + auto [mesh_, es, size] = c.ensure_scenery_mesh(_draw_array); for (const auto& x : es) - { - fm_assert(x.e); add_clickable(shader, win_size, x.data.in, x.data, list); - const auto& e = *x.e; - const auto depth0 = e.depth_offset(); - const auto depth1 = depth0[1]*TILE_MAX_DIM + depth0[0]; - const auto depth = tile_shader::depth_value(e.coord.local(), depth1); - const auto pos0 = Vector3(e.coord.local()) * TILE_SIZE + Vector3(Vector2(e.offset), 0); - auto& atlas = *e.atlas; - const auto pos = atlas.frame_quad(pos0, e.r, e.frame); - const auto& g = atlas.group(e.r); - const auto texcoords = atlas.texcoords_for_frame(e.r, e.frame, !g.mirror_from.isEmpty()); - for (auto i = 0uz; i < 4; i++) - array[k][i] = { pos[i], texcoords[i], depth }; - atlases[k] = &atlas; + GL::MeshView mesh{mesh_}; + [[maybe_unused]] size_t draw_count = 0; + const auto max_index = uint32_t(size*quad_index_count - 1); + + const auto do_draw = [&](size_t from, size_t to, anim_atlas* atlas) { + atlas->texture().bind(0); + mesh.setCount((int)(quad_index_count * (to-from))); + mesh.setIndexRange((int)(from*quad_index_count), 0, max_index); + shader.draw(mesh); + draw_count++; + }; + + fm_debug_assert(size_t(mesh_.count()) <= size*quad_index_count); + + struct last_ { + anim_atlas* atlas = nullptr; size_t run_from = 0; + operator bool() const { return atlas; } + last_& operator=(std::nullptr_t) { atlas = nullptr; return *this; } + } last; + size_t i = 0; - if (++k >= 1) + for (auto k = 0uz; k < size; k++) + { + fm_assert(es[k].e); + auto& e = *es[k].e; + auto& atlas = *e.atlas; + if (last.atlas && &atlas != last.atlas) { - _batch_vertex_buffer.setSubData(0, { array.data(), k }); - for (uint32_t i = 0; i < k; i++) - do_draw(shader, mesh, last_atlas, atlases[i], i); - k = 0; + //Debug{} << "draw-static" << es[last.run_from].e->atlas->name() << es[last.run_from].e->ordinal() << Vector2i(es[last.run_from].e->coord.local()) << i - last.run_from; + do_draw(last.run_from, i, last.atlas); + last = {}; + } + if (e.is_dynamic()) + { + const auto depth0 = e.depth_offset(); + const auto depth1 = depth0[1]*TILE_MAX_DIM + depth0[0]; + const auto depth = tile_shader::depth_value(e.coord.local(), depth1); + //Debug{} << "draw-dyn" << e.atlas->name() << e.ordinal() << Vector2i(e.coord.local()); + draw(shader, atlas, e.r, e.frame, e.coord.local(), e.offset, depth); + last = {}; + } + else + { + if (!last.atlas) + last = { &atlas, i }; + i++; } } - - if (k > 0) + if (last.atlas && i != last.run_from) { - _batch_vertex_buffer.setSubData(0, ArrayView<const quad_data>{array.data(), k}); - for (uint32_t i = 0; i < k; i++) - do_draw(shader, mesh, last_atlas, atlases[i], i); + //Debug{} << "draw-last" << last.atlas->name() << es[es.size()-1].e->ordinal() << Vector2i(es[es.size()-1].e->coord.local()) << i - last.run_from; + do_draw(last.run_from, i, last.atlas); } + + //Debug{} << "--" << i << draw_count << "--"; std::fflush(stdout); } void anim_mesh::draw(tile_shader& shader, anim_atlas& atlas, rotation r, size_t frame, const Vector3& center, float depth) diff --git a/draw/anim.hpp b/draw/anim.hpp index 93900caf..eaa191f5 100644 --- a/draw/anim.hpp +++ b/draw/anim.hpp @@ -34,9 +34,7 @@ struct anim_mesh final std::vector<clickable>& list); private: - static constexpr size_t batch_size = 256, quad_index_count = 6; - static std::array<UnsignedShort, quad_index_count> make_index_array(); - static std::array<std::array<UnsignedShort, quad_index_count>, batch_size> make_batch_index_array(); + static std::array<UnsignedShort, 6> make_index_array(); struct vertex_data final { Vector3 position; @@ -49,10 +47,6 @@ private: GL::Mesh _mesh; GL::Buffer _vertex_buffer{quad_data{}, Magnum::GL::BufferUsage::DynamicDraw}, _index_buffer{make_index_array()}; - - GL::Mesh _batch_mesh{NoCreate}; - GL::Buffer _batch_vertex_buffer{std::array<quad_data, batch_size>{}, Magnum::GL::BufferUsage::DynamicDraw}, - _batch_index_buffer{make_batch_index_array()}; }; } // namespace floormat diff --git a/src/chunk-scenery.cpp b/src/chunk-scenery.cpp index 40a99487..66f6a733 100644 --- a/src/chunk-scenery.cpp +++ b/src/chunk-scenery.cpp @@ -132,7 +132,55 @@ auto chunk::ensure_scenery_mesh(Array<entity_draw_order>& array) noexcept -> sce std::sort(array.begin(), array.begin() + size, [](const auto& a, const auto& b) { return a.ord < b.ord; }); topological_sort(array, size); - return { ArrayView<entity_draw_order>{array, size} }; + const auto es = ArrayView<entity_draw_order>{array, size}; + + if (_scenery_modified) + { + _scenery_modified = false; + + const auto count = fm_begin( + size_t ret = 0; + for (const auto& [e, ord, _data] : es) + ret += !e->is_dynamic(); + return ret; + ); + + scenery_indexes.clear(); + scenery_indexes.reserve(count); + scenery_vertexes.clear(); + scenery_vertexes.reserve(count); + + for (const auto& [e, ord, _data] : es) + { + if (e->is_dynamic()) + continue; + + const auto i = scenery_indexes.size(); + scenery_indexes.emplace_back(tile_atlas::indices(i)); + const auto& atlas = e->atlas; + const auto& fr = *e; + const auto pos = e->coord.local(); + const auto coord = Vector3(pos) * TILE_SIZE + Vector3(Vector2(fr.offset), 0); + const auto quad = atlas->frame_quad(coord, fr.r, fr.frame); + const auto& group = atlas->group(fr.r); + const auto texcoords = atlas->texcoords_for_frame(fr.r, fr.frame, !group.mirror_from.isEmpty()); + const float depth = tile_shader::depth_value(pos, tile_shader::scenery_depth_offset); + scenery_vertexes.emplace_back(); + auto& v = scenery_vertexes.back(); + for (auto j = 0uz; j < 4; j++) + v[j] = { quad[j], texcoords[j], depth }; + } + + GL::Mesh mesh{GL::MeshPrimitive::Triangles}; + mesh.addVertexBuffer(GL::Buffer{scenery_vertexes}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) + .setIndexBuffer(GL::Buffer{scenery_indexes}, 0, GL::MeshIndexType::UnsignedShort) + .setCount(int32_t(6 * count)); + scenery_mesh = Utility::move(mesh); + } + + fm_assert(!size || es); + + return { scenery_mesh, es, size }; } void chunk::ensure_scenery_draw_array(Array<entity_draw_order>& array) diff --git a/src/chunk-scenery.hpp b/src/chunk-scenery.hpp index 067f176a..cbe2ea83 100644 --- a/src/chunk-scenery.hpp +++ b/src/chunk-scenery.hpp @@ -25,7 +25,9 @@ struct chunk::entity_draw_order topo_sort_data data; }; struct chunk::scenery_mesh_tuple { + GL::Mesh& mesh; ArrayView<entity_draw_order> array; + size_t size; }; } // namespace floormat diff --git a/src/chunk.hpp b/src/chunk.hpp index db6f96f7..be90c89a 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -125,7 +125,7 @@ private: std::vector<std::array<vertex, 4>> scenery_vertexes; struct world* _world; - GL::Mesh ground_mesh{NoCreate}, wall_mesh{NoCreate}; + GL::Mesh ground_mesh{NoCreate}, wall_mesh{NoCreate}, scenery_mesh{NoCreate}; RTree _rtree; |