From 9436414c5002e86e64f90be3f10933fdba63943e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 1 Oct 2022 19:35:43 +0200 Subject: a --- chunk.cpp | 49 ++++++++++++++ chunk.hpp | 162 +++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 14 ++-- shaders/tile-shader.frag | 10 +-- shaders/tile-shader.vert | 15 +++-- tile-shader.cpp | 44 +++---------- tile-shader.hpp | 16 +---- tile.hpp | 135 --------------------------------------- 8 files changed, 247 insertions(+), 198 deletions(-) create mode 100644 chunk.cpp create mode 100644 chunk.hpp diff --git a/chunk.cpp b/chunk.cpp new file mode 100644 index 00000000..87cbe0cf --- /dev/null +++ b/chunk.cpp @@ -0,0 +1,49 @@ +#include "chunk.hpp" + +namespace Magnum::Examples { + +chunk_sampler_array::chunk_sampler_array() +{ + samplers.reserve(MAX_SAMPLERS); +} + +void chunk_sampler_array::ensure_sampler(std::size_t tile_id, const shared_sampler& x) +{ + CORRADE_INTERNAL_ASSERT(tile_id < TILE_COUNT); + if (std::size_t id = sampler_map[tile_id]; id != 0) + { + const shared_sampler& old_sampler = samplers[id]; + if (x == old_sampler) + return; + } + CORRADE_INTERNAL_ASSERT(samplers.size() < MAX_SAMPLERS); + const auto id = (std::uint8_t)samplers.size(); + samplers.push_back(x); + sampler_map[tile_id] = id; +} + +void chunk_sampler_array::clear() +{ + Magnum::GL::AbstractTexture::unbindImages(0, samplers.size()); + samplers.clear(); + sampler_map = {}; +} + +void chunk_sampler_array::bind() +{ + Magnum::GL::AbstractTexture::unbindImages(0, MAX_SAMPLERS); + for (std::size_t i = 0; i < samplers.size(); i++) + samplers[i]->texture().bind((int)i + 1); +} + +std::shared_ptr chunk_sampler_array::operator[](std::size_t tile_id) const +{ + CORRADE_INTERNAL_ASSERT(tile_id < TILE_COUNT); + std::size_t sampler_id = sampler_map[tile_id] - 1; + CORRADE_INTERNAL_ASSERT(sampler_id < samplers.size()); + const auto& sampler = samplers[sampler_id]; + CORRADE_INTERNAL_ASSERT(sampler != nullptr); + return sampler; +} + +} // namespace Magnum::Examples diff --git a/chunk.hpp b/chunk.hpp new file mode 100644 index 00000000..99ad1778 --- /dev/null +++ b/chunk.hpp @@ -0,0 +1,162 @@ +#pragma once +#include "tile.hpp" +#include +#include + +namespace Magnum::Examples { + +static constexpr std::size_t TILE_MAX_DIM = 16; +static constexpr std::size_t TILE_COUNT = TILE_MAX_DIM*TILE_MAX_DIM; + +struct local_coords final { + std::uint8_t x = 0, y = 0; + constexpr std::size_t to_index() const noexcept; +}; + +constexpr std::size_t local_coords::to_index() const noexcept { + return y*TILE_MAX_DIM + x; +} + +struct chunk_coords final { + std::int16_t x = 0, y = 0; + constexpr std::size_t to_index() const noexcept; + + static constexpr std::size_t max_bits = sizeof(chunk_coords::x)*8 * 3 / 4; + static_assert(max_bits*4/3/8 == sizeof(decltype(chunk_coords::x))); +}; + +struct chunk_sampler_array final { + using shared_sampler = std::shared_ptr; + using sampler_tuple = std::pair; + + static constexpr inline int MAX_SAMPLERS = 16; + std::vector> samplers; + std::array sampler_map = {}; + + chunk_sampler_array(); + void ensure_sampler(std::size_t tile_id, const shared_sampler& x); + std::shared_ptr operator[](std::size_t tile_id) const; + void clear(); + void bind(); + + static_assert(MAX_SAMPLERS <= 0xff); +}; + +struct global_coords final { + std::uint32_t x = 0, y = 0; + constexpr global_coords() noexcept = default; + constexpr global_coords(decltype(x) x, decltype(y) y) noexcept : x{x}, y{y} {} + constexpr global_coords(chunk_coords c, local_coords tile) noexcept; +}; + +static_assert(std::is_same_v); +static_assert(std::is_same_v); + +struct chunk final +{ + using index_type = decltype(local_coords::x); + using tile_index_array_type = std::array; + //static constexpr inline local_coords center = { (index_type)(N/2), (index_type)(N/2) }; + + constexpr tile& operator[](local_coords xy); + constexpr const tile& operator[](local_coords xy) const; + constexpr tile& operator[](std::size_t i); + constexpr const tile& operator[](std::size_t i) const; + + template + requires std::invocable + constexpr inline void foreach_tile(F&& fun) { foreach_tile_(std::forward(fun)); } + + template + requires std::invocable + constexpr inline void foreach_tile(F&& fun) const { foreach_tile_(std::forward(fun)); } + +private: + template constexpr void foreach_tile_(F&& fun); + + std::array tiles = {}; + chunk_sampler_array samplers; +}; + +constexpr tile& chunk::operator[](std::size_t i) { + if (i >= TILE_COUNT) + throw OUT_OF_RANGE(i, 0, TILE_COUNT); + return tiles[i]; +} + +constexpr const tile& chunk::operator[](std::size_t i) const { + return const_cast(*this).operator[](i); +} + +constexpr const tile& chunk::operator[](local_coords xy) const { + return const_cast(*this).operator[](xy); +} + +constexpr tile& chunk::operator[](local_coords xy) +{ + auto idx = xy.to_index(); + return operator[](idx); +} + +template +constexpr void chunk::foreach_tile_(F&& fun) +{ + constexpr auto N = TILE_MAX_DIM; + for (unsigned j = 0; j < N; j++) + for (unsigned i = 0; i < N; i++) + { + unsigned idx = j*N + i; + fun(const_cast(*this).tiles[idx], i, j); + } +} + +constexpr std::size_t chunk_coords::to_index() const noexcept +{ + using unsigned_type = std::make_unsigned_t; + using limits = std::numeric_limits; + constexpr auto N = limits::max() + std::size_t{1}; + static_assert(sizeof(unsigned_type) <= sizeof(UnsignedInt)/2); + return (std::size_t)(unsigned_type)y * N + (std::size_t)(unsigned_type)x; +} + +struct hash_chunk final { + constexpr std::size_t operator()(chunk_coords xy) const noexcept { + return hash{}(xy.to_index()); + } +}; + +struct world final +{ + static_assert(sizeof(chunk_coords::x) <= sizeof(std::size_t)/2); + + explicit world() = default; + template std::shared_ptr ensure_chunk(chunk_coords xy, F&& fun); + +private: + std::unordered_map, hash_chunk> chunks; +}; + +template +std::shared_ptr world::ensure_chunk(chunk_coords xy, F&& fun) +{ + ASSERT(xy.x < 1 << chunk_coords::max_bits); + ASSERT(xy.y < 1 << chunk_coords::max_bits); + + auto it = chunks.find(xy); + if (it != chunks.end()) + return it->second; + else + { + std::shared_ptr ptr{fun()}; + ASSERT(ptr); + return chunks[xy] = std::move(ptr); + } +} + +constexpr global_coords::global_coords(chunk_coords c, local_coords tile) noexcept : + x{tile.x + ((std::uint32_t)(std::make_unsigned_t)c.x << chunk_coords::max_bits)}, + y{tile.y + ((std::uint32_t)(std::make_unsigned_t)c.y << chunk_coords::max_bits)} +{ +} + +} // namespace Magnum::Examples diff --git a/main.cpp b/main.cpp index b5a3f6ca..89afe091 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include "tile-shader.hpp" #include "defs.hpp" #include "tile.hpp" +#include "chunk.hpp" #include @@ -72,6 +73,7 @@ struct app final : Platform::Application std::uint64_t time_ticks = 0, time_freq = SDL_GetPerformanceFrequency(); Vector2 camera_offset; enum_bitset keys; + chunk c; float get_dt(); static constexpr Vector3 TILE_SIZE = { 50, 50, 50 }; @@ -106,8 +108,9 @@ app::app(const Arguments& arguments): vertices.clear(); indices.clear(); int k = 0; - for (unsigned j = 0; j < chunk::N; j++) // TODO draw walls in correct order - for (unsigned i = 0; i < chunk::N; i++) + constexpr auto N = TILE_MAX_DIM; + for (unsigned j = 0; j < N; j++) // TODO draw walls in correct order + for (unsigned i = 0; i < N; i++) { auto positions = floor1->floor_quad({(float)(X*i), (float)(Y*j), 0}, {X, Y}); auto texcoords = floor1->texcoords_for_id(k % floor1->size()); @@ -130,7 +133,8 @@ app::app(const Arguments& arguments): indices.clear(); { - Vector3 center{chunk::N/2.f*TILE_SIZE[0], chunk::N/2.f*TILE_SIZE[1], 0}; + constexpr auto N = TILE_MAX_DIM; + Vector3 center{N/2.f*TILE_SIZE[0], N/2.f*TILE_SIZE[1], 0}; tile_atlas::vertex_array_type walls[] = { wall1->wall_quad_W(center, Vector3(X, Y, Z)), wall1->wall_quad_N(center, Vector3(X, Y, Z)), @@ -221,7 +225,7 @@ void app::do_camera(float dt) void app::reset_camera_offset() { - camera_offset = _shader.project({chunk::N*TILE_SIZE[0]/2.f, chunk::N*TILE_SIZE[1]/2.f, 0}); + camera_offset = _shader.project({TILE_MAX_DIM*TILE_SIZE[0]/2.f, TILE_MAX_DIM*TILE_SIZE[1]/2.f, 0}); } void app::update(float dt) @@ -280,7 +284,7 @@ void app::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event) } // namespace Magnum::Examples -MAGNUM_APPLICATION_MAIN(Magnum::Examples::app); +MAGNUM_APPLICATION_MAIN(Magnum::Examples::app) #ifdef _MSC_VER # include diff --git a/shaders/tile-shader.frag b/shaders/tile-shader.frag index f75a0478..8a31a1e1 100644 --- a/shaders/tile-shader.frag +++ b/shaders/tile-shader.frag @@ -1,12 +1,14 @@ +#version 450 precision highp float; -layout(location = 2) uniform sampler2D textureData; - -in vec2 interpolatedTextureCoordinates; +const int MAX_SAMPLERS = 16; +layout (location = 0) uniform sampler2D samplers[MAX_SAMPLERS]; +layout (location = 0) in vec2 texcoord; +layout (location = 1) flat in uint sampler_id; out vec4 fragmentColor; void main() { - fragmentColor.rgb = texture(textureData, interpolatedTextureCoordinates).rgb; + fragmentColor.rgb = texture(samplers[sampler_id], texcoord).rgb; fragmentColor.a = 1; } diff --git a/shaders/tile-shader.vert b/shaders/tile-shader.vert index 239f4b07..6c12f1e2 100644 --- a/shaders/tile-shader.vert +++ b/shaders/tile-shader.vert @@ -1,14 +1,19 @@ +#version 450 precision highp float; +layout (location = 0) uniform vec2 scale; +layout (location = 1) uniform vec2 offset; + layout(location = 0) in vec4 position; -layout(location = 1) in vec2 textureCoordinates; -layout(location = 0) uniform vec2 scale; -layout(location = 3) uniform vec2 offset; +layout(location = 1) in vec2 texcoord; +layout(location = 2) flat in uint sampler_id; -out vec2 interpolatedTextureCoordinates; +layout (location = 0) out vec2 out_texcoord; +layout (location = 1) flat out uint out_sampler_id; void main() { - interpolatedTextureCoordinates = textureCoordinates; + interpolatedTextureCoordinates = texcoord; + out_sampler_id = sampler_id; float cx = 2/scale.x, cy = 2/scale.y; float x = position.y, y = position.x, z = position.z; diff --git a/tile-shader.cpp b/tile-shader.cpp index b04054b4..64e23ed1 100644 --- a/tile-shader.cpp +++ b/tile-shader.cpp @@ -19,21 +19,19 @@ tile_shader::tile_shader() vert.addSource(loader.shader("shaders/tile-shader.vert")); frag.addSource(loader.shader("shaders/tile-shader.frag")); +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); - +#ifdef __clang__ +# pragma clang diagnostic pop +#endif attachShaders({vert, frag}); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); setUniform(ScaleUniform, Vector2{640, 480}); - - samplers.reserve(MAX_SAMPLERS); -} - -tile_shader& tile_shader::bind_texture(GL::Texture2D& texture, int id) -{ - texture.bind(id); - return *this; } tile_shader& tile_shader::set_scale(const Vector2& scale) @@ -42,6 +40,7 @@ tile_shader& tile_shader::set_scale(const Vector2& scale) setUniform(ScaleUniform, scale); return *this; } + tile_shader& tile_shader::set_camera_offset(Vector2 camera_offset) { CORRADE_INTERNAL_ASSERT(std::fabs(camera_offset[0]) <= std::scalbn(1.f, std::numeric_limits::digits)); @@ -50,36 +49,11 @@ tile_shader& tile_shader::set_camera_offset(Vector2 camera_offset) setUniform(OffsetUniform, camera_offset); return *this; } + Vector2 tile_shader::project(Vector3 pt) { float x = pt[1], y = pt[0], z = pt[2]; return { x-y, (x+y+z*2)*.75f }; } -int tile_shader::bind_sampler(const tile_shader::shared_sampler& atlas) -{ - CORRADE_INTERNAL_ASSERT(samplers.size() < MAX_SAMPLERS); - auto sampler_comparator = [](const sampler_tuple& a, const sampler_tuple& b) { - const auto& [ptr1, n1] = a; - const auto& [ptr2, n2] = b; - return ptr1.get() < ptr2.get(); - }; - auto it = std::lower_bound(samplers.begin(), samplers.end(), - sampler_tuple{atlas, -1}, sampler_comparator); - int idx; - if (it == samplers.end()) { - idx = (int)samplers.size(); - samplers.emplace_back(atlas, idx); - } else - idx = it->second; - atlas->texture().bind(idx); - return idx; -} - -void tile_shader::clear_samplers() -{ - Magnum::GL::AbstractTexture::unbindImages(0, samplers.size()); - samplers.clear(); -} - } // namespace Magnum::Examples diff --git a/tile-shader.hpp b/tile-shader.hpp index ed771969..bf0813ff 100644 --- a/tile-shader.hpp +++ b/tile-shader.hpp @@ -14,12 +14,9 @@ namespace Magnum::Examples { struct tile_shader : GL::AbstractShaderProgram { - using shared_sampler = std::shared_ptr; - using sampler_tuple = std::pair; - typedef GL::Attribute<0, Vector3> Position; typedef GL::Attribute<1, Vector2> TextureCoordinates; - typedef GL::Attribute<2, int> SamplerId; + typedef GL::Attribute<2, int> TextureID; explicit tile_shader(); @@ -30,19 +27,10 @@ struct tile_shader : GL::AbstractShaderProgram static Vector2 project(Vector3 pt); - [[nodiscard]] int bind_sampler(const shared_sampler& atlas); - void clear_samplers(); - - tile_shader& bind_texture(GL::Texture2D& texture, int id); - private: - std::vector samplers; Vector2 scale_, camera_offset_; - static constexpr int MAX_SAMPLERS = 16; - - enum { SamplerIdAttribute = 1, }; - enum { ScaleUniform = 0, OffsetUniform = 3, }; + enum { ScaleUniform = 0, OffsetUniform = 1, }; }; } // namespace Magnum::Examples diff --git a/tile.hpp b/tile.hpp index 19a0354e..2c23aa9a 100644 --- a/tile.hpp +++ b/tile.hpp @@ -34,140 +34,5 @@ struct tile final //explicit operator bool() const noexcept { return !!ground_image_.atlas; } }; -struct local_coords final { - std::uint8_t x = 0, y = 0; - constexpr std::size_t to_index() const noexcept; -}; - -struct chunk_coords final { - std::int16_t x = 0, y = 0; - constexpr std::size_t to_index() const noexcept; - - static constexpr std::size_t max_bits = sizeof(chunk_coords::x)*8 * 3 / 4; - static_assert(max_bits*4/3/8 == sizeof(decltype(chunk_coords::x))); -}; - -struct global_coords final { - std::uint32_t x = 0, y = 0; - constexpr global_coords() noexcept = default; - constexpr global_coords(decltype(x) x, decltype(y) y) noexcept : x{x}, y{y} {} - constexpr global_coords(chunk_coords c, local_coords tile) noexcept; -}; - -static_assert(std::is_same_v); -static_assert(std::is_same_v); -static_assert(std::is_same_v); - -struct chunk final -{ - static constexpr std::size_t N = 16; - static constexpr std::size_t TILE_COUNT = N*N; - - using index_type = decltype(local_coords::x); - using tile_index_array_type = std::array; - //static constexpr inline local_coords center = { (index_type)(N/2), (index_type)(N/2) }; - - constexpr tile& operator[](local_coords xy); - constexpr const tile& operator[](local_coords xy) const; - constexpr tile& operator[](std::size_t i); - constexpr const tile& operator[](std::size_t i) const; - - template - requires std::invocable - constexpr inline void foreach_tile(F&& fun) { foreach_tile_(std::forward(fun)); } - - template - requires std::invocable - constexpr inline void foreach_tile(F&& fun) const { foreach_tile_(std::forward(fun)); } - -private: - template constexpr void foreach_tile_(F&& fun); - - std::array tiles = {}; -}; - -constexpr std::size_t local_coords::to_index() const noexcept { - return y*chunk::N + x; -} - -constexpr tile& chunk::operator[](std::size_t i) { - if (i >= TILE_COUNT) - throw OUT_OF_RANGE(i, 0, TILE_COUNT); - return tiles[i]; -} - -constexpr const tile& chunk::operator[](std::size_t i) const { - return const_cast(*this).operator[](i); -} - -constexpr const tile& chunk::operator[](local_coords xy) const { - return const_cast(*this).operator[](xy); -} - -constexpr tile& chunk::operator[](local_coords xy) -{ - auto idx = xy.to_index(); - return operator[](idx); -} - -template -constexpr void chunk::foreach_tile_(F&& fun) -{ - for (unsigned j = 0; j < N; j++) - for (unsigned i = 0; i < N; i++) - { - unsigned idx = j*N + i; - fun(const_cast(*this).tiles[idx], i, j); - } -} - -constexpr std::size_t chunk_coords::to_index() const noexcept -{ - using unsigned_type = std::make_unsigned_t; - using limits = std::numeric_limits; - constexpr auto N = limits::max() + std::size_t{1}; - static_assert(sizeof(unsigned_type) <= sizeof(UnsignedInt)/2); - return (std::size_t)(unsigned_type)y * N + (std::size_t)(unsigned_type)x; -} - -struct hash_chunk final { - constexpr std::size_t operator()(chunk_coords xy) const noexcept { - return hash{}(xy.to_index()); - } -}; - -struct world final -{ - static_assert(sizeof(chunk_coords::x) <= sizeof(std::size_t)/2); - - explicit world() = default; - template std::shared_ptr ensure_chunk(chunk_coords xy, F&& fun); - -private: - std::unordered_map, hash_chunk> chunks; -}; - -template -std::shared_ptr world::ensure_chunk(chunk_coords xy, F&& fun) -{ - ASSERT(xy.x < 1 << chunk_coords::max_bits); - ASSERT(xy.y < 1 << chunk_coords::max_bits); - - auto it = chunks.find(xy); - if (it != chunks.end()) - return it->second; - else - { - std::shared_ptr ptr{fun()}; - ASSERT(ptr); - return chunks[xy] = std::move(ptr); - } -} - -constexpr global_coords::global_coords(chunk_coords c, local_coords tile) noexcept : - x{tile.x + ((std::uint32_t)(std::make_unsigned_t)c.x << chunk_coords::max_bits)}, - y{tile.y + ((std::uint32_t)(std::make_unsigned_t)c.y << chunk_coords::max_bits)} -{ -} } //namespace Magnum::Examples -- cgit v1.2.3