summaryrefslogtreecommitdiffhomepage
path: root/draw
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-12-08 08:13:37 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-12-08 08:29:12 +0100
commitab31f0ed81301c23d6847f3ca1513d4b90275de7 (patch)
tree735d63bd525eccabc43ebc75e804469e898950af /draw
parentb26ddfcee60de0951f0feaf4ae4e12551853ee21 (diff)
draw, main, src/chunk: batch scenery writes
Diffstat (limited to 'draw')
-rw-r--r--draw/anim.cpp88
-rw-r--r--draw/anim.hpp16
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 {