diff options
-rw-r--r-- | main.cpp | 36 | ||||
-rw-r--r-- | tile-shader.cpp | 34 | ||||
-rw-r--r-- | tile-shader.hpp | 20 |
3 files changed, 68 insertions, 22 deletions
@@ -60,12 +60,13 @@ struct app final : Platform::Application GL::Mesh _mesh, _mesh2; tile_shader _shader; - std::shared_ptr<tile_atlas> atlas = + std::shared_ptr<tile_atlas> floor1 = //loader.tile_atlas("../share/game/images/tiles.tga", {8,4}); //loader.tile_atlas("../share/game/images/tiles2.tga", {8,5}); loader.tile_atlas("../share/game/images/metal1.tga", {2, 2}); //loader.tile_atlas("../share/game/images/floor1.tga", {4, 4}); - std::shared_ptr<tile_atlas> atlas2 = + std::shared_ptr<tile_atlas> floor2 = loader.tile_atlas("../share/game/images/floor1.tga", {4, 4}); + std::shared_ptr<tile_atlas> wall1 = loader.tile_atlas("../share/game/images/metal2.tga", {2, 2}); std::uint64_t time_ticks = 0, time_freq = SDL_GetPerformanceFrequency(); @@ -108,9 +109,9 @@ app::app(const Arguments& arguments): for (unsigned j = 0; j < chunk::N; j++) // TODO draw walls in correct order for (unsigned i = 0; i < chunk::N; i++) { - auto positions = atlas->floor_quad({(float)(X*i), (float)(Y*j), 0}, {X, Y}); - auto texcoords = atlas->texcoords_for_id(k % atlas->size()); - auto indices_ = atlas->indices(k); + auto positions = floor1->floor_quad({(float)(X*i), (float)(Y*j), 0}, {X, Y}); + auto texcoords = floor1->texcoords_for_id(k % floor1->size()); + auto indices_ = floor1->indices(k); for (unsigned x = 0; x < 4; x++) vertices.push_back({ positions[x], texcoords[x] }); @@ -131,17 +132,17 @@ app::app(const Arguments& arguments): { Vector3 center{chunk::N/2.f*TILE_SIZE[0], chunk::N/2.f*TILE_SIZE[1], 0}; tile_atlas::vertex_array_type walls[] = { - atlas2->wall_quad_W(center, Vector3(X, Y, Z)), - atlas2->wall_quad_N(center, Vector3(X, Y, Z)), - atlas2->wall_quad_E(center, Vector3(X, Y, Z)), - atlas2->wall_quad_S(center, Vector3(X, Y, Z)), + wall1->wall_quad_W(center, Vector3(X, Y, Z)), + wall1->wall_quad_N(center, Vector3(X, Y, Z)), + wall1->wall_quad_E(center, Vector3(X, Y, Z)), + wall1->wall_quad_S(center, Vector3(X, Y, Z)), }; int k = 0; for (const auto& positions : walls) { - auto texcoords = atlas2->texcoords_for_id(k % atlas2->size()); - auto indices_ = atlas2->indices(k); + auto texcoords = wall1->texcoords_for_id(k % wall1->size()); + auto indices_ = wall1->indices(k); for (unsigned x = 0; x < 4; x++) vertices.push_back({ positions[x], texcoords[x] }); for (auto x : indices_) @@ -184,15 +185,16 @@ void app::drawEvent() { } } + _shader.clear_samplers(); + + auto floor1_sampler = _shader.bind_sampler(floor1); + auto wall_sampler = _shader.bind_sampler(wall1); + #if 1 - _shader - .bindTexture(atlas->texture()) - .draw(_mesh); + _shader.draw(_mesh); #endif #if 1 - _shader - .bindTexture(atlas2->texture()) - .draw(_mesh2); + _shader.draw(_mesh2); #endif swapBuffers(); diff --git a/tile-shader.cpp b/tile-shader.cpp index d00a1ed9..b04054b4 100644 --- a/tile-shader.cpp +++ b/tile-shader.cpp @@ -1,6 +1,6 @@ #include "tile-shader.hpp" #include "loader.hpp" - +#include <algorithm> #include <Corrade/Containers/Reference.h> #include <Corrade/Utility/Resource.h> #include <Magnum/GL/Context.h> @@ -26,11 +26,13 @@ tile_shader::tile_shader() CORRADE_INTERNAL_ASSERT_OUTPUT(link()); setUniform(ScaleUniform, Vector2{640, 480}); + + samplers.reserve(MAX_SAMPLERS); } -tile_shader& tile_shader::bindTexture(GL::Texture2D& texture) +tile_shader& tile_shader::bind_texture(GL::Texture2D& texture, int id) { - texture.bind(TextureUnit); + texture.bind(id); return *this; } @@ -54,4 +56,30 @@ Vector2 tile_shader::project(Vector3 pt) 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 34348814..ed771969 100644 --- a/tile-shader.hpp +++ b/tile-shader.hpp @@ -1,16 +1,25 @@ #pragma once +#include "tile-atlas.hpp" +#include <vector> +#include <utility> #include <Magnum/GL/AbstractShaderProgram.h> #include <Magnum/GL/Texture.h> #include <Magnum/Math/Color.h> #include <Magnum/Math/Vector2.h> #include <Magnum/Math/Matrix4.h> +struct tile_atlas; + namespace Magnum::Examples { struct tile_shader : GL::AbstractShaderProgram { + using shared_sampler = std::shared_ptr<tile_atlas>; + using sampler_tuple = std::pair<shared_sampler, int>; + typedef GL::Attribute<0, Vector3> Position; typedef GL::Attribute<1, Vector2> TextureCoordinates; + typedef GL::Attribute<2, int> SamplerId; explicit tile_shader(); @@ -21,11 +30,18 @@ struct tile_shader : GL::AbstractShaderProgram static Vector2 project(Vector3 pt); - tile_shader& bindTexture(GL::Texture2D& texture); + [[nodiscard]] int bind_sampler(const shared_sampler& atlas); + void clear_samplers(); + + tile_shader& bind_texture(GL::Texture2D& texture, int id); private: + std::vector<sampler_tuple> samplers; Vector2 scale_, camera_offset_; - enum { TextureUnit = 0 }; + + static constexpr int MAX_SAMPLERS = 16; + + enum { SamplerIdAttribute = 1, }; enum { ScaleUniform = 0, OffsetUniform = 3, }; }; |