diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chunk-walls.cpp | 131 | ||||
-rw-r--r-- | src/chunk.hpp | 2 | ||||
-rw-r--r-- | src/wall-atlas.cpp | 1 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 11 | ||||
-rw-r--r-- | src/wall-defs.hpp | 2 |
5 files changed, 136 insertions, 11 deletions
diff --git a/src/chunk-walls.cpp b/src/chunk-walls.cpp index 82bae536..9e808b41 100644 --- a/src/chunk-walls.cpp +++ b/src/chunk-walls.cpp @@ -4,7 +4,8 @@ #include "wall-atlas.hpp" #include "shaders/shader.hpp" #include <Corrade/Containers/ArrayViewStl.h> -#include <Corrade/Containers/PairStl.h> +#include <Corrade/Containers/Pair.h> +#include <Corrade/Containers/Optional.h> #include <utility> #include <algorithm> #include <ranges> @@ -34,6 +35,30 @@ using Wall::Direction_; // ----------------------- +constexpr Quads::quad get_corner(Direction_ D, Group_ G, float depth) +{ + CORRADE_ASSUME(D < Direction_::COUNT); + CORRADE_ASSUME(G < Group_::COUNT); + constexpr Vector2 half_tile = TILE_SIZE2*.5f; + constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z(); + const bool is_west = D == Wall::Direction_::W; + + if (!is_west) + return {{ + {-X, -Y, 0 }, + {-X, -Y, Z }, + {-X - depth, -Y, 0 }, + {-X - depth, -Y, Z }, + }}; + else + return {{ + {-X, -Y - depth, 0 }, + {-X, -Y - depth, Z }, + {-X, -Y, 0 }, + {-X, -Y, Z }, + }}; +} + constexpr Quads::quad get_quad(Direction_ D, Group_ G, float depth) { CORRADE_ASSUME(D < Direction_::COUNT); @@ -100,6 +125,8 @@ constexpr Quads::quad get_quad(Direction_ D, Group_ G, float depth) { -X, Y, Z } }}; } + case corner: + return get_corner(D, G, depth); } std::unreachable(); fm_abort("invalid wall_atlas group '%d'", (int)G); @@ -148,7 +175,8 @@ GL::Mesh chunk::make_wall_mesh() for (uint32_t k = 0; k < 2*TILE_COUNT; k++) { - const auto D = k & 1 ? Wall::Direction_::W : Wall::Direction_::N; + const bool is_west = k & 1; + const auto D = is_west ? Wall::Direction_::W : Wall::Direction_::N; const auto& atlas = _walls->atlases[k]; if (!atlas) continue; @@ -157,23 +185,112 @@ GL::Mesh chunk::make_wall_mesh() const auto center = Vector3(pos) * TILE_SIZE; const auto& dir = atlas->calc_direction(D); const auto vpos = (uint8_t)Vector2ui(global_coords{_coord, pos}.raw()).sum(); + const auto Depth = atlas->info().depth; - for (auto [_, member, G] : Wall::Direction::groups) + for (auto [_, member, G] : Wall::Direction::groups_for_draw) { CORRADE_ASSUME(G < Group_::COUNT); - const auto& group = dir.*member; - if (!group.is_defined) + bool corner_ok = false; + + if (!(dir.*member).is_defined) continue; + + if (!is_west) + { + switch (G) + { + default: + break; + case Wall::Group_::side: + if (auto t2 = at_offset_(pos, {1, 0}); t2 && t2->wall_west_atlas()) + continue; + else if (auto t2 = at_offset_(pos, {1, -1}); t2 && t2->wall_west_atlas()) + continue; + else if (auto t2 = at_offset_(pos, {-1, 0}); t2 && !t2->wall_north_atlas()) + if (auto t2 = at_offset_(pos, {0, -1}); t2 && t2->wall_west_atlas()) + corner_ok = true; + break; + } + } + else + { + switch (G) + { + default: + break; + case Wall::Group_::side: + if (auto t2 = at_offset_(pos, {0, 1}); t2 && t2->wall_north_atlas()) + continue; + else if (auto t2 = at_offset_(pos, {-1, 1}); t2 && t2->wall_north_atlas()) + continue; + else if (auto t2 = at_offset_(pos, {0, -1}); t2 && !t2->wall_west_atlas()) + if (auto t2 = at_offset_(pos, {-1, 0}); t2 && t2->wall_north_atlas()) + corner_ok = true; + break; + } + } + const auto depth_offset = depth_offset_for_group(G); - auto quad = get_quad(D, G, atlas->info().depth); + auto quad = get_quad(D, G, Depth); for (auto& v : quad) v += center; + if (corner_ok) + { + if (dir.corner.is_defined) + { + const auto frames = atlas->frames(dir.corner); + auto variant = (variant_ != (uint8_t)-1 ? variant_ : vpos); + variant += frames.size(); + if (!is_west) + variant -= 1; + else + variant += 1; + variant %= frames.size(); + const auto& frame = frames[variant]; + const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size()); + const auto i = N++; + _walls->mesh_indexes[i] = (uint16_t)k; + const auto depth = tile_shader::depth_value(pos, depth_offset); + fm_debug_assert(i < vertexes.size()); + auto& v = vertexes[i]; + auto quad = get_quad(D, Group_::corner, Depth); + for (auto& v : quad) + v += center; + for (uint8_t j = 0; j < 4; j++) + v[j] = { quad[j], texcoords[j], depth }; + } + else if (dir.wall.is_defined) [[likely]] + { + const auto frames = atlas->frames(dir.wall); + auto variant = (variant_ != (uint8_t)-1 ? variant_ : vpos); + variant += frames.size() - 1; + variant %= frames.size(); + const auto& frame = frames[variant]; + fm_assert(frame.size.x() > Depth); + auto start = frame.offset + Vector2ui(frame.size.x(), 0) - Vector2ui{Depth, 0}; + const auto texcoords = Quads::texcoords_at(start, {Depth, frame.size.y()}, atlas->image_size()); + const auto i = N++; + _walls->mesh_indexes[i] = (uint16_t)k; + const auto depth = tile_shader::depth_value(pos, depth_offset); + fm_debug_assert(i < vertexes.size()); + auto& v = vertexes[i]; + auto quad = get_corner(D, G, Depth); + for (auto& v : quad) + v += center; + for (uint8_t j = 0; j < 4; j++) + v[j] = { quad[j], texcoords[j], depth }; + } + } + + const auto& group = dir.*member; + const auto frames = atlas->frames(group); + const auto i = N++; fm_debug_assert(i < max_wall_quad_count); _walls->mesh_indexes[i] = (uint16_t)k; - const auto frames = atlas->frames(group); + const auto variant = (variant_ != (uint8_t)-1 ? variant_ : vpos) % frames.size(); const auto& frame = frames[variant]; const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size()); diff --git a/src/chunk.hpp b/src/chunk.hpp index 89892d90..f2434281 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -124,7 +124,7 @@ struct chunk final // for drawing only static constexpr size_t max_wall_quad_count = - TILE_COUNT*Wall::Direction_COUNT*Wall::Group_COUNT; + TILE_COUNT*Wall::Direction_COUNT*(Wall::Group_COUNT+4); private: struct ground_stuff diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp index fa6e99a6..9461431c 100644 --- a/src/wall-atlas.cpp +++ b/src/wall-atlas.cpp @@ -93,6 +93,7 @@ Vector2ui wall_atlas::expected_size(unsigned depth, Group_ group) return { size.x(), size.z() }; case top: case side: + case corner: return { depth, size.z() }; default: std::unreachable(); diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index e9421653..9a329a74 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -46,21 +46,28 @@ struct Direction using memfn_ptr = Group Direction::*; struct member_tuple { StringView name; memfn_ptr member; Group_ tag; }; - Group wall{}, side{}, top{}; + Group wall{}, side{}, top{}, corner{}; const Group& group(Group_ i) const; const Group& group(size_t i) const; Group& group(Group_ i); Group& group(size_t i); + bool operator==(const Direction&) const noexcept; + static constexpr inline member_tuple groups[] = { { "wall"_s, &Direction::wall, Group_::wall }, { "side"_s, &Direction::side, Group_::side }, { "top"_s, &Direction::top, Group_::top }, + { "corner"_s, &Direction::corner, Group_::corner }, }; static_assert(std::size(groups) == (size_t)Group_::COUNT); - bool operator==(const Direction&) const noexcept; + static constexpr inline member_tuple groups_for_draw[] = { + { "wall"_s, &Direction::wall, Group_::wall }, + { "side"_s, &Direction::side, Group_::side }, + { "top"_s, &Direction::top, Group_::top }, + }; }; struct Info diff --git a/src/wall-defs.hpp b/src/wall-defs.hpp index ea36605b..a19d560b 100644 --- a/src/wall-defs.hpp +++ b/src/wall-defs.hpp @@ -3,7 +3,7 @@ namespace floormat::Wall { -enum class Group_ : uint8_t { wall, side, top, COUNT }; +enum class Group_ : uint8_t { wall, side, top, corner, COUNT }; enum class Direction_ : uint8_t { N, W, COUNT }; |