diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-12-08 08:13:37 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-12-08 08:29:12 +0100 |
commit | ab31f0ed81301c23d6847f3ca1513d4b90275de7 (patch) | |
tree | 735d63bd525eccabc43ebc75e804469e898950af /draw | |
parent | b26ddfcee60de0951f0feaf4ae4e12551853ee21 (diff) |
draw, main, src/chunk: batch scenery writes
Diffstat (limited to 'draw')
-rw-r--r-- | draw/anim.cpp | 88 | ||||
-rw-r--r-- | draw/anim.hpp | 16 |
2 files changed, 99 insertions, 5 deletions
diff --git a/draw/anim.cpp b/draw/anim.cpp index 951c7f5a..df3011da 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -2,8 +2,12 @@ #include "anim-atlas.hpp" #include "chunk.hpp" #include "shaders/tile.hpp" +#include "main/clickable.hpp" +#include <Magnum/GL/MeshView.h> #include <Magnum/GL/Texture.h> +//#define FM_DEBUG_DRAW_COUNT + namespace floormat { anim_mesh::anim_mesh() @@ -22,6 +26,85 @@ std::array<UnsignedShort, 6> anim_mesh::make_index_array() }}; } +void anim_mesh::add_clickable(tile_shader& shader, const Vector2i& win_size, + chunk_coords c, std::uint8_t i, const std::shared_ptr<anim_atlas>& atlas, scenery& s, + std::vector<clickable_scenery>& clickable) +{ + const local_coords xy{i}; + const auto& g = atlas->group(s.r); + const auto& f = atlas->frame(s.r, s.frame); + const auto world_pos = TILE_SIZE20 * Vector3(xy.x, xy.y, 0) + Vector3(g.offset); + const Vector2ui offset((Vector2(shader.camera_offset()) + Vector2(win_size)*.5f) + + shader.project(world_pos) - Vector2(f.ground)); + clickable_scenery item = { + *atlas, s, + { f.offset, f.offset + f.size }, { offset, offset + f.size }, + atlas->bitmask(), tile_shader::depth_value(xy, tile_shader::scenery_depth_offset), c, xy, + !g.mirror_from.isEmpty(), + }; + clickable.push_back(item); +} + +void anim_mesh::draw(tile_shader& shader, chunk& c) +{ + constexpr auto quad_index_count = 6; + auto [mesh_, ids, size] = c.ensure_scenery_mesh(); + struct { anim_atlas* atlas = nullptr; std::size_t pos = 0; } last; + GL::MeshView mesh{mesh_}; + anim_atlas* bound = nullptr; + + [[maybe_unused]] std::size_t draw_count = 0; + + const auto do_draw = [&](std::size_t i, anim_atlas* atlas, std::uint32_t max_index, bool force) { + if (!force && atlas == last.atlas) + return; + if (auto len = i - last.pos; last.atlas && len > 0) + { + if (last.atlas != bound) + last.atlas->texture().bind(0); + bound = last.atlas; + mesh.setCount((int)(quad_index_count * len)); + mesh.setIndexRange((int)(last.pos*quad_index_count), 0, max_index); + shader.draw(mesh); + draw_count++; + } + last = { atlas, i }; + }; + + constexpr auto next_is_dynamic = [](chunk& c, std::size_t i) { + for (; i < TILE_COUNT; i++) + if (auto [atlas, s] = c[i].scenery(); atlas && atlas->info().fps == 0) + return false; + return true; + }; + + const auto draw_dynamic = [&](std::size_t last_id, std::size_t id) { + for (std::size_t i = last_id+1; i < id; i++) + if (auto [atlas, s] = c[i].scenery(); atlas && atlas->info().fps > 0) + { + draw(shader, *atlas, s.r, s.frame, local_coords{i}); + bound = nullptr; + } + }; + + const auto max_index = std::uint32_t(size*quad_index_count - 1); + std::size_t k, last_id = 0; + for (k = 0; k < size; k++) + { + const auto id = ids[k]; + draw_dynamic(last_id, id); + do_draw(k, c.scenery_atlas_at(id), max_index, next_is_dynamic(c, id+1)); + last_id = id; + } + draw_dynamic(size == 0 ? 0 : ids.back(), TILE_COUNT); + do_draw(size, nullptr, max_index, true); + +#ifdef FM_DEBUG_DRAW_COUNT + if (draw_count) + fm_debug("anim draws: %zu", draw_count); +#endif +} + void anim_mesh::draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, const Vector3& center, float depth) { const auto pos = atlas.frame_quad(center, r, frame); @@ -37,7 +120,10 @@ void anim_mesh::draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::si void anim_mesh::draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, local_coords xy) { - draw(shader, atlas, r, frame, Vector3(xy.x, xy.y, 0.f) * TILE_SIZE, tile_shader::depth_value(xy, .25f)); + const auto pos = Vector3(xy.x, xy.y, 0.f) * TILE_SIZE; + const float depth = tile_shader::depth_value(xy, tile_shader::scenery_depth_offset); + draw(shader, atlas, r, frame, pos, depth); } + } // namespace floormat diff --git a/draw/anim.hpp b/draw/anim.hpp index e11d45ae..263d851d 100644 --- a/draw/anim.hpp +++ b/draw/anim.hpp @@ -1,7 +1,5 @@ #pragma once - #include "local-coords.hpp" -#include "scenery.hpp" #include <array> #include <Corrade/Containers/ArrayViewStl.h> #include <Magnum/Magnum.h> @@ -9,6 +7,8 @@ #include <Magnum/Math/Vector3.h> #include <Magnum/GL/Mesh.h> #include <Magnum/GL/Buffer.h> +#include "src/scenery.hpp" +#include "main/clickable.hpp" //namespace floormat::Serialize { struct anim_frame; } @@ -17,13 +17,21 @@ namespace floormat { struct tile_shader; struct anim_atlas; struct chunk; -//using anim_frame = Serialize::anim_frame; +template<typename Atlas, typename T> struct clickable; +struct scenery; struct anim_mesh final { + using clickable_scenery = clickable<anim_atlas, scenery>; + anim_mesh(); - void draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, local_coords xy); + + void draw(tile_shader& shader, chunk& c); void draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, const Vector3& pos, float depth); + void draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, local_coords xy); + static void add_clickable(tile_shader& shader, const Vector2i& win_size, + chunk_coords c, std::uint8_t i, const std::shared_ptr<anim_atlas>& atlas, scenery& s, + std::vector<clickable_scenery>& clickable); private: struct vertex_data final { |