summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-09 18:27:32 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-09 18:27:32 +0100
commit5907a8902e6f01774cebbb515349a66c86a47fb3 (patch)
tree7d3f90a38e038e0f4acbaf62b328fb23446ab7c7
parent1febb02d958fa4cf8c15e3ca18f9d644f9fc80fb (diff)
allow drawing walls in random order
-rw-r--r--draw/anim.cpp2
-rw-r--r--draw/floor.hpp3
-rw-r--r--draw/wall.cpp127
-rw-r--r--draw/wall.hpp39
-rw-r--r--editor/tile-editor.cpp3
-rw-r--r--loader/loader-impl.cpp1
-rw-r--r--shaders/tile.cpp4
-rw-r--r--shaders/tile.hpp2
-rw-r--r--src/chunk.cpp102
-rw-r--r--src/chunk.hpp25
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