diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-09 18:27:32 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-09 18:27:32 +0100 |
commit | 5907a8902e6f01774cebbb515349a66c86a47fb3 (patch) | |
tree | 7d3f90a38e038e0f4acbaf62b328fb23446ab7c7 | |
parent | 1febb02d958fa4cf8c15e3ca18f9d644f9fc80fb (diff) |
allow drawing walls in random order
-rw-r--r-- | draw/anim.cpp | 2 | ||||
-rw-r--r-- | draw/floor.hpp | 3 | ||||
-rw-r--r-- | draw/wall.cpp | 127 | ||||
-rw-r--r-- | draw/wall.hpp | 39 | ||||
-rw-r--r-- | editor/tile-editor.cpp | 3 | ||||
-rw-r--r-- | loader/loader-impl.cpp | 1 | ||||
-rw-r--r-- | shaders/tile.cpp | 4 | ||||
-rw-r--r-- | shaders/tile.hpp | 2 | ||||
-rw-r--r-- | src/chunk.cpp | 102 | ||||
-rw-r--r-- | src/chunk.hpp | 25 |
10 files changed, 143 insertions, 165 deletions
diff --git a/draw/anim.cpp b/draw/anim.cpp index dac23566..a096711c 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -27,7 +27,7 @@ void anim_mesh::draw(tile_shader& shader, const anim_atlas& atlas, rotation r, s const auto center = Vector3(xy.x, xy.y, 0.f) * TILE_SIZE; const auto pos = atlas.frame_quad(center, r, frame); const auto texcoords = atlas.texcoords_for_frame(r, frame); - const float depth = tile_shader::depth_value(xy); + const float depth = tile_shader::depth_value(xy, .25f); quad_data array; for (std::size_t i = 0; i < 4; i++) array[i] = { pos[i], texcoords[i], depth }; diff --git a/draw/floor.hpp b/draw/floor.hpp index bfff7948..74547857 100644 --- a/draw/floor.hpp +++ b/draw/floor.hpp @@ -2,15 +2,12 @@ namespace floormat { -struct tile_ref; struct tile_shader; struct chunk; struct floor_mesh final { floor_mesh(); - floor_mesh(floor_mesh&&) = delete; - floor_mesh(const floor_mesh&) = delete; void draw(tile_shader& shader, chunk& c); }; diff --git a/draw/wall.cpp b/draw/wall.cpp index 0096946e..2008fe05 100644 --- a/draw/wall.cpp +++ b/draw/wall.cpp @@ -9,110 +9,49 @@ namespace floormat { -constexpr auto quad_index_count = 6; +#define FM_DEBUG_DRAW_COUNT -wall_mesh::wall_mesh() -{ - _mesh.setCount((int)(quad_index_count * COUNT)) - .addVertexBuffer(_vertex_buffer, 0, tile_shader::TextureCoordinates{}) - .addVertexBuffer(_constant_buffer, 0, tile_shader::Position{}, tile_shader::Depth{}) - .setIndexBuffer(_index_buffer, 0, GL::MeshIndexType::UnsignedShort); - CORRADE_INTERNAL_ASSERT(_mesh.isIndexed()); -} - -void wall_mesh::add_wall(vertex_array& data, texture_array& textures, const tile_image_ref& img, std::size_t pos) -{ - CORRADE_INTERNAL_ASSERT(pos < data.size()); - auto texcoords = img.atlas->texcoords_for_id(img.variant); - for (std::size_t i = 0; i < 4; i++) - { - data[pos][i] = { texcoords[i] }; - textures[pos] = &img.atlas->texture(); - } -} +constexpr auto quad_index_count = 6; -void wall_mesh::maybe_add_tile(vertex_array& data, texture_array& textures, tile_ref x, std::size_t pos) -{ - if (auto wall = x.wall_north(); wall.atlas) - add_wall(data, textures, wall, pos * 2 + 0); - if (auto wall = x.wall_west(); wall.atlas) - add_wall(data, textures, wall, pos * 2 + 1); -} +wall_mesh::wall_mesh() = default; void wall_mesh::draw(tile_shader& shader, chunk& c) { - //_texcoord_buffer.setData({nullptr, sizeof(vertex_array)}, Magnum::GL::BufferUsage::DynamicDraw); // orphan the buffer - texture_array textures = {}; - { - vertex_array data; - for (auto [x, idx, pt] : c) { - maybe_add_tile(data, textures, x, idx); - } - _vertex_buffer.setSubData(0, data); - } + auto [mesh_, ids_n, ids_w] = c.ensure_wall_mesh(); - const GL::Texture2D* last_texture = nullptr; - Magnum::GL::MeshView mesh{_mesh}; - for (std::size_t idx = 0; idx < TILE_COUNT; idx++) - { - for (std::size_t i = idx*2; i <= idx*2+1; i++) - if (auto* const tex = textures[i]; tex) - { - mesh.setCount(quad_index_count); - mesh.setIndexRange((int)(i*quad_index_count), 0, quad_index_count*COUNT - 1); - if (tex != last_texture) - tex->bind(0); - last_texture = tex; - shader.draw(mesh); - } - if (auto a = c[idx].scenery(); a.atlas) - { - auto& tex = a.atlas->texture(); - if (&tex != last_texture) - tex.bind(0); - last_texture = &a.atlas->texture(); - auto frame = a.frame; -#if 1 - static std::size_t f = 0; - f++; - if (f > a.atlas->info().nframes * 3) - f = 0; - frame.frame = (scenery::frame_t)std::min(f, a.atlas->info().nframes - 1); -#endif - _anim_mesh.draw(shader, *a.atlas, a.frame.r, frame.frame, local_coords{idx}); - } - } -} + tile_atlas* last_atlas = nullptr; + std::size_t last_pos = 0; + GL::MeshView mesh{mesh_}; -std::array<std::array<UnsignedShort, 6>, wall_mesh::COUNT> wall_mesh::make_index_array() -{ - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) - std::array<std::array<UnsignedShort, 6>, COUNT> array; + [[maybe_unused]] std::size_t draw_count = 0; - for (std::size_t i = 0; i < std::size(array); i++) - array[i] = tile_atlas::indices(i); - return array; -} - -auto wall_mesh::make_constant_array() -> std::array<std::array<constant, 4>, wall_mesh::COUNT> -{ - std::array<std::array<constant, 4>, COUNT> array; - for (std::uint8_t j = 0; j < TILE_MAX_DIM; j++) - for (std::uint8_t i = 0; i < TILE_MAX_DIM; i++) + const auto do_draw = [&](std::size_t i, tile_atlas* atlas) { + if (atlas == last_atlas) + return; + if (auto len = i - last_pos; last_atlas && len > 0) { - const local_coords coord{i, j}; - const std::size_t idx = coord.to_index() * 2u; - const auto center = Vector3(i, j, 0) * TILE_SIZE; - auto wall_n_pos = tile_atlas::wall_quad_N(center, TILE_SIZE); - auto wall_w_pos = tile_atlas::wall_quad_W(center, TILE_SIZE); - auto depth = tile_shader::depth_value(coord); - for (std::size_t k = 0; k < 4; k++) - { - array[idx + 0][k] = { wall_n_pos[k], depth, }; - array[idx + 1][k] = { wall_w_pos[k], depth, }; - } + last_atlas->texture().bind(0); + mesh.setCount((int)(quad_index_count * len)); + mesh.setIndexRange((int)(last_pos*quad_index_count), 0, quad_index_count*TILE_COUNT - 1); + shader.draw(mesh); + draw_count++; } - return array; + last_atlas = atlas; + last_pos = i; + }; + + for (std::size_t k = 0; k < TILE_COUNT; k++) + if (auto* atlas = c.wall_n_atlas_at(ids_n[k])) + do_draw(k, atlas); + for (std::size_t k = 0; k < TILE_COUNT; k++) + if (auto* atlas = c.wall_w_atlas_at(ids_w[k])) + do_draw(k + TILE_COUNT, atlas); + do_draw(TILE_COUNT*2, nullptr); + +#ifdef FM_DEBUG_DRAW_COUNT + if (draw_count) + fm_debug("wall draws: %zu", draw_count); +#endif } } // namespace floormat diff --git a/draw/wall.hpp b/draw/wall.hpp index d65744fd..ace24904 100644 --- a/draw/wall.hpp +++ b/draw/wall.hpp @@ -1,53 +1,16 @@ #pragma once -#include "tile-defs.hpp" -#include "anim.hpp" -#include <array> -#include <Corrade/Containers/ArrayViewStl.h> -#include <Magnum/Math/Vector2.h> -#include <Magnum/Math/Vector3.h> -#include <Magnum/GL/Mesh.h> -#include <Magnum/GL/Buffer.h> - namespace floormat { struct tile_shader; struct chunk; -struct tile_ref; -struct tile_image_ref; struct wall_mesh final { wall_mesh(); - void draw(tile_shader& shader, chunk& c); - -private: - static constexpr auto COUNT1 = TILE_MAX_DIM*2, COUNT = COUNT1 * COUNT1; - - struct vertex final { - Vector2 texcoords; - }; - struct constant final { - Vector3 position; - float depth = -1; - }; - - using quad = std::array<vertex, 4>; - using vertex_array = std::array<quad, COUNT>; - using texture_array = std::array<GL::Texture2D*, COUNT>; - - anim_mesh _anim_mesh; - - static void maybe_add_tile(vertex_array& data, texture_array& textures, tile_ref x, std::size_t pos); - static void add_wall(vertex_array& data, texture_array& textures, const tile_image_ref& img, std::size_t pos); + void draw(tile_shader& shader, chunk& c); - GL::Mesh _mesh; - GL::Buffer _vertex_buffer{vertex_array{}, Magnum::GL::BufferUsage::DynamicDraw}, - _index_buffer{make_index_array()}, - _constant_buffer{make_constant_array()}; - static std::array<std::array<UnsignedShort, 6>, COUNT> make_index_array(); - static std::array<std::array<constant, 4>, COUNT> make_constant_array(); }; } // namespace floormat diff --git a/editor/tile-editor.cpp b/editor/tile-editor.cpp index 6e4da967..66ca1e7b 100644 --- a/editor/tile-editor.cpp +++ b/editor/tile-editor.cpp @@ -147,15 +147,16 @@ tile_image_proto tile_editor::get_selected() void tile_editor::place_tile(world& world, global_coords pos, const tile_image_proto& img) { auto [c, t] = world[pos]; - c.mark_modified(); switch (_mode) { case editor_mode::none: break; case editor_mode::floor: + c.mark_ground_modified(); t.ground() = img; break; case editor_mode::walls: + c.mark_walls_modified(); switch (_rotation) { case editor_wall_rotation::N: diff --git a/loader/loader-impl.cpp b/loader/loader-impl.cpp index c4ba2376..6b2fe986 100644 --- a/loader/loader-impl.cpp +++ b/loader/loader-impl.cpp @@ -84,6 +84,7 @@ std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub s } template<std::size_t N> +fm_noinline Trade::ImageData2D loader_impl::texture(const char(&prefix)[N], StringView filename_) { if constexpr(N > 1) diff --git a/shaders/tile.cpp b/shaders/tile.cpp index c8261acd..22a91497 100644 --- a/shaders/tile.cpp +++ b/shaders/tile.cpp @@ -66,11 +66,11 @@ void tile_shader::_draw() } } -float tile_shader::depth_value(const local_coords& xy) noexcept +float tile_shader::depth_value(const local_coords& xy, float offset) noexcept { constexpr float max = (TILE_MAX_DIM+1)*(TILE_MAX_DIM+1) * .5f; constexpr float min = -1 + 1.f/256; - float value = min + xy.to_index()/max; + float value = min + (xy.to_index() + offset)/max; fm_assert(value > -1 && value < 1); return value; } diff --git a/shaders/tile.hpp b/shaders/tile.hpp index 8a45e1e7..4acc556b 100644 --- a/shaders/tile.hpp +++ b/shaders/tile.hpp @@ -27,7 +27,7 @@ struct tile_shader : GL::AbstractShaderProgram tile_shader& set_camera_offset(Vector2d camera_offset); Vector4 tint() const { return _tint; } tile_shader& set_tint(const Vector4& tint); - static float depth_value(const local_coords& xy) noexcept; + static float depth_value(const local_coords& xy, float offset = 0) noexcept; template<typename T = float> static constexpr Math::Vector2<T> project(const Math::Vector3<T>& pt); template<typename T = float> static constexpr Math::Vector2<T> unproject(const Math::Vector2<T>& px); diff --git a/src/chunk.cpp b/src/chunk.cpp index 0cfb4959..e736fe42 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -24,20 +24,25 @@ bool chunk::empty(bool force) const noexcept return true; } -tile_atlas* chunk::ground_atlas_at(std::size_t i) const noexcept -{ - return _ground_atlases[i].get(); -} +tile_atlas* chunk::ground_atlas_at(std::size_t i) const noexcept { return _ground_atlases[i].get(); } +tile_atlas* chunk::wall_n_atlas_at(std::size_t i) const noexcept { return _wall_north_atlases[i].get(); } +tile_atlas* chunk::wall_w_atlas_at(std::size_t i) const noexcept { return _wall_west_atlases[i].get(); } -static constexpr auto make_index_array() +static auto make_index_array(std::size_t offset) { - std::array<std::array<UnsignedShort, 6>, TILE_COUNT> array; + std::array<std::array<UnsignedShort, 6>, TILE_COUNT> array; // NOLINT(cppcoreguidelines-pro-type-member-init) for (std::size_t i = 0; i < TILE_COUNT; i++) - array[i] = tile_atlas::indices(i); + array[i] = tile_atlas::indices(i + offset); return array; } -auto chunk::ensure_ground_mesh() noexcept -> mesh_tuple +struct vertex { + Vector3 position; + Vector2 texcoords; + float depth = -1; +}; + +auto chunk::ensure_ground_mesh() noexcept -> ground_mesh_tuple { if (!_ground_modified) return { ground_mesh, ground_indexes }; @@ -49,11 +54,6 @@ auto chunk::ensure_ground_mesh() noexcept -> mesh_tuple return _ground_atlases[a].get() < _ground_atlases[b].get(); }); - struct vertex { - Vector3 position; - Vector2 texcoords; - float depth = -1; - }; std::array<std::array<vertex, 4>, TILE_COUNT> vertexes; for (std::size_t k = 0; k < TILE_COUNT; k++) { @@ -71,7 +71,7 @@ auto chunk::ensure_ground_mesh() noexcept -> mesh_tuple v[j] = { quad[j], texcoords[j], depth }; } } - constexpr auto indexes = make_index_array(); + const auto indexes = make_index_array(0); GL::Mesh mesh{GL::MeshPrimitive::Triangles}; mesh.addVertexBuffer(GL::Buffer{vertexes}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) @@ -81,6 +81,69 @@ auto chunk::ensure_ground_mesh() noexcept -> mesh_tuple return { ground_mesh, ground_indexes }; } +auto chunk::ensure_wall_mesh() noexcept -> wall_mesh_tuple +{ + if (!_walls_modified) + return { wall_mesh, wall_n_indexes, wall_w_indexes }; + _walls_modified = false; + + for (std::size_t i = 0; i < TILE_COUNT; i++) + wall_n_indexes[i] = std::uint8_t(i); + for (std::size_t i = 0; i < TILE_COUNT; i++) + wall_w_indexes[i] = std::uint8_t(i); + + std::sort(wall_n_indexes.begin(), wall_n_indexes.end(), [this](std::uint8_t a, std::uint8_t b) { + return _wall_north_atlases[a].get() < _wall_north_atlases[b].get(); + }); + std::sort(wall_w_indexes.begin(), wall_w_indexes.end(), [this](std::uint8_t a, std::uint8_t b) { + return _wall_west_atlases[a].get() < _wall_west_atlases[b].get(); + }); + + std::array<std::array<vertex, 4>, TILE_COUNT> vertexes[2] = {}; + + using ids_ = std::array<std::uint8_t, TILE_COUNT>; + using a_ = std::array<std::shared_ptr<tile_atlas>, TILE_COUNT>; + using vs_ = std::array<variant_t, TILE_COUNT>; + using verts_ = std::array<std::array<vertex, 4>, TILE_COUNT>; + constexpr auto do_walls = [](const ids_& ids, const a_& as, const vs_& vs, verts_& verts, const auto& fn) { + for (std::size_t k = 0; k < TILE_COUNT; k++) + { + const std::uint8_t i = ids[k]; + if (const auto& atlas = as[i]; !atlas) + verts[k] = {}; + else + { + const local_coords pos{i}; + const float depth = tile_shader::depth_value(pos); + const std::array<Vector3, 4> quad = fn(*atlas, pos); + const auto texcoords = atlas->texcoords_for_id(vs[i] % atlas->num_tiles()); + auto& v = verts[k]; + for (std::size_t j = 0; j < 4; j++) + v[j] = { quad[j], texcoords[j], depth, }; + } + } + }; + do_walls(wall_n_indexes, _wall_north_atlases, _wall_north_variants, vertexes[0], + [](const tile_atlas& a, local_coords pos) { + return a.wall_quad_N(Vector3(pos.x, pos.y, 0) * TILE_SIZE, TILE_SIZE); + }); + do_walls(wall_w_indexes, _wall_west_atlases, _wall_west_variants, vertexes[1], + [](const tile_atlas& a, local_coords pos) { + return a.wall_quad_W(Vector3(pos.x, pos.y, 0) * TILE_SIZE, TILE_SIZE); + }); + + using index_t = std::array<std::array<UnsignedShort, 6>, TILE_COUNT>; + const index_t indexes[2] = { make_index_array(0), make_index_array(TILE_COUNT) }; + + GL::Mesh mesh{GL::MeshPrimitive::Triangles}; + mesh.addVertexBuffer(GL::Buffer{vertexes}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) + .setIndexBuffer(GL::Buffer{indexes}, 0, GL::MeshIndexType::UnsignedShort) + .setCount(6 * TILE_COUNT); + wall_mesh = Utility::move(mesh); + return { wall_mesh, wall_n_indexes, wall_w_indexes }; +} + +fm_noinline chunk::chunk() noexcept // NOLINT(modernize-use-equals-default) { //fm_debug("chunk ctor"); @@ -101,14 +164,13 @@ auto chunk::end() const noexcept -> const_iterator { return cend(); } chunk::chunk(chunk&&) noexcept = default; chunk& chunk::operator=(chunk&&) noexcept = default; -void chunk::mark_modified() noexcept -{ - _ground_modified = true; -} +void chunk::mark_ground_modified() noexcept { _ground_modified = true; } +void chunk::mark_walls_modified() noexcept { _walls_modified = true; } -bool chunk::is_modified() const noexcept +void chunk::mark_modified() noexcept { - return _ground_modified; + mark_ground_modified(); + mark_walls_modified(); } } // namespace floormat diff --git a/src/chunk.hpp b/src/chunk.hpp index 1f16a9c1..1b702d81 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -39,14 +39,27 @@ struct chunk final chunk(chunk&&) noexcept; chunk& operator=(chunk&&) noexcept; + void mark_ground_modified() noexcept; + void mark_walls_modified() noexcept; void mark_modified() noexcept; - bool is_modified() const noexcept; - struct mesh_tuple { GL::Mesh& mesh; const std::array<std::uint8_t, TILE_COUNT>& ids; }; // NOLINT + struct ground_mesh_tuple final { + GL::Mesh& mesh; + const std::array<std::uint8_t, TILE_COUNT>& ids; + }; + struct wall_mesh_tuple final { + GL::Mesh& mesh; + const std::array<std::uint8_t, TILE_COUNT>& n; + const std::array<std::uint8_t, TILE_COUNT>& w; + }; - mesh_tuple ensure_ground_mesh() noexcept; + ground_mesh_tuple ensure_ground_mesh() noexcept; tile_atlas* ground_atlas_at(std::size_t i) const noexcept; + wall_mesh_tuple ensure_wall_mesh() noexcept; + tile_atlas* wall_n_atlas_at(std::size_t i) const noexcept; + tile_atlas* wall_w_atlas_at(std::size_t i) const noexcept; + private: std::array<std::shared_ptr<tile_atlas>, TILE_COUNT> _ground_atlases, _wall_north_atlases, _wall_west_atlases; std::array<std::shared_ptr<anim_atlas>, TILE_COUNT> _scenery_atlases; @@ -54,9 +67,11 @@ private: std::array<variant_t, TILE_COUNT> _ground_variants = {}, _wall_north_variants = {}, _wall_west_variants = {}; std::bitset<TILE_COUNT*2> _passability = {}; std::array<std::uint8_t, TILE_COUNT> ground_indexes = {}; - GL::Mesh ground_mesh{NoCreate}; + std::array<std::uint8_t, TILE_COUNT> wall_n_indexes = {}, wall_w_indexes = {}; + GL::Mesh ground_mesh{NoCreate}, wall_mesh{NoCreate}; mutable std::uint8_t _maybe_empty : 1 = true, - _ground_modified : 1 = true; + _ground_modified : 1 = true, + _walls_modified : 1 = true; }; } // namespace floormat |