Commit 979c8395 authored by Florian Oetke's avatar Florian Oetke
Browse files

optimized level rendering/culling code

parent 536f094b
Pipeline #3379 failed with stage
in 3 minutes and 34 seconds
Subproject commit a75972722af8eef63c531085703c680d535e1a2d
Subproject commit e4f5314a25e5a7ea821819e9d6471acf16af99fd
......@@ -81,6 +81,8 @@ namespace phase_shifter {
_global_render->update(dt);
_global_render->draw();
_renderer_factory->finish_frame();
_global_render->device().wait_idle();
}
} // namespace phase_shifter
......@@ -14,6 +14,34 @@ namespace phase_shifter::level {
using namespace mirrage::ecs::components;
using namespace mirrage::util;
namespace {
using action = std::function<auto(const Tileset& tileset,
const std::string& key,
const Tile& tile,
const glm::vec3& position)
->void>;
template <typename F>
auto for_each(const Level& level, F&& action)
{
auto& tiles = level.tileset->tiles;
auto offset = level.tileset->tile_size;
glm::vec3 position{0.f};
for(auto&& row : level.tiles) {
position.x = 0.f;
for(auto&& tile_key : row) {
std::string key(1, tile_key);
if(auto tile_it = tiles.find(key); tile_it != tiles.end()) {
auto& tile = tile_it->second;
action(level.tileset.get_blocking(), key, tile, position);
position.x += offset;
}
}
position.z += offset;
}
}
} // namespace
Level_system::Level_system(mirrage::ecs::Entity_manager& entities, mirrage::asset::Asset_manager& assets)
: _entities(entities), _assets(assets)
{
......@@ -57,43 +85,107 @@ namespace phase_shifter::level {
auto Level_system::update(const mirrage::util::Time& time) -> void {}
namespace {
using action = std::function<auto(const Tileset& tileset,
const std::string& key,
const Tile& tile,
const glm::vec3& position)
->void>;
void Level_system::draw(mirrage::renderer::Deferred_renderer& renderer)
{
auto cam = renderer.active_camera();
if(cam.is_nothing())
return;
auto for_each(const Level& level, const action& action)
{
auto& tiles = level.tileset->tiles;
auto offset = level.tileset->tile_size;
glm::vec3 position{0.f};
for(auto&& row : level.tiles) {
position.x = 0.f;
for(auto&& tile_key : row) {
std::string key(1, tile_key);
if(auto tile_it = tiles.find(key); tile_it != tiles.end()) {
auto& tile = tile_it->second;
action(level.tileset.get_blocking(), key, tile, position);
position.x += offset;
auto& level = _current_level.get_blocking();
auto level_size_x = level.tiles[0].size();
auto level_size_y = level.tiles.size();
auto& render_queue = renderer.low_level_draw_queue();
auto offset = level.tileset->tile_size;
glm::vec3 position{0.f};
auto viewport = cam.get_or_throw().viewport;
auto screen_to_world_in_plane = [&](glm::vec2 sp) {
auto wp = glm::unProject(glm::vec3{sp, 1.f},
glm::mat4{1.f},
cam.get_or_throw().pure_projection,
cam.get_or_throw().viewport);
wp = glm::vec3{cam.get_or_throw().inv_view * glm::vec4{wp, 1.f}};
auto dir = glm::normalize(wp - cam.get_or_throw().eye_position);
if(dir.y == 0)
return glm::vec3(0, 0, 0);
else {
auto t = (glm::dot(glm::vec3(0, 1, 0), glm::vec3(0, 0, 0))
- glm::dot(glm::vec3(0, 1, 0), cam.get_or_throw().eye_position))
/ glm::dot(glm::vec3(0, 1, 0), dir);
return cam.get_or_throw().eye_position + dir * t;
}
};
auto top_left = glm::vec3(999999.f, 999999.f, 999999.f);
auto bottom_right = glm::vec3(0, 0, 0);
for(auto& p : {glm::vec2(0, 0),
glm::vec2(viewport.z, 0),
glm::vec2(0, viewport.w),
glm::vec2(viewport.z, viewport.w)}) {
auto wp = screen_to_world_in_plane(p);
top_left.x = std::min(top_left.x, wp.x);
top_left.y = std::min(top_left.y, wp.y);
top_left.z = std::min(top_left.z, wp.z);
bottom_right.x = std::max(bottom_right.x, wp.x);
bottom_right.y = std::max(bottom_right.y, wp.y);
bottom_right.z = std::max(bottom_right.z, wp.z);
}
top_left /= offset;
bottom_right /= offset;
auto min_x = static_cast<std::size_t>(
std::clamp(std::floor(top_left.x) - 1, 0.f, static_cast<float>(level_size_x)));
auto min_y = static_cast<std::size_t>(
std::clamp(std::floor(top_left.z) - 1, 0.f, static_cast<float>(level_size_y)));
auto max_x = static_cast<std::size_t>(
std::clamp(std::ceil(bottom_right.x) + 1, 0.f, static_cast<float>(level_size_x)));
auto max_y = static_cast<std::size_t>(
std::clamp(std::ceil(bottom_right.z) + 1, 0.f, static_cast<float>(level_size_y)));
for(auto y = min_y; y < max_y; y++) {
for(auto x = min_x; x < max_x; x++) {
auto tile = level.tiles[y][x];
auto model_ptr = _tile_models.find(tile);
if(model_ptr != _tile_models.end() && model_ptr->second.ready()) {
auto& model = model_ptr->second.get_blocking();
auto& submeshes = model.sub_meshes();
for(auto&& submesh_index : mirrage::util::range(submeshes.size())) {
auto& geometry = render_queue.emplace_back();
geometry.model = &model;
geometry.sub_mesh = std::uint32_t(submesh_index);
geometry.position = glm::vec3(x, 0, y) * offset;
geometry.scale = glm::vec3(2, 2, 2);
geometry.orientation = glm::angleAxis(0.f, glm::vec3{0.f, 1.f, 0.f});
geometry.substance_id = submeshes[submesh_index].material->substance_id();
geometry.culling_mask = ~std::uint32_t(0);
}
}
position.z += offset;
}
}
} // namespace
}
auto Level_system::load(const std::string& name) -> void
{
_current_level = _assets.load<Level>(mirrage::asset::AID("level:" + name));
auto& level = _current_level.get_blocking();
for_each(level, [&](auto&, const std::string& key, const Tile& tile, const glm::vec3& position) {
_entities.entity_builder(tile.blueprint).position(position).create();
if(tile.spawn) {
_spawn_function(key)(tile, position);
}
});
_tile_models.clear();
for(auto&& [id, tile] : level.tileset->tiles) {
_tile_models[id[0]] =
_assets.load<mirrage::renderer::Model>(mirrage::asset::AID("model:" + tile.blueprint));
}
}
auto Level_system::ray_cast(const glm::vec2& origin, const glm::vec2& direction)
......
......@@ -3,6 +3,8 @@
#include "../util/collision.hpp"
#include "level.hpp"
#include <mirrage/renderer/deferred_renderer.hpp>
#include <mirrage/renderer/model.hpp>
#include <mirrage/utils/maybe.hpp>
#include <mirrage/utils/units.hpp>
......@@ -25,6 +27,8 @@ namespace phase_shifter::level {
Level_system(mirrage::ecs::Entity_manager& entities, mirrage::asset::Asset_manager& assets);
auto update(const mirrage::util::Time& time) -> void;
void draw(mirrage::renderer::Deferred_renderer& renderer);
auto load(const std::string& name) -> void;
auto ray_cast(const glm::vec2& origin, const glm::vec2& direction) -> std::pair<bool, util::Contact>;
void check_contacts(glm::vec2 origin, float radius, std::function<void(util::Contact)>) const;
......@@ -38,5 +42,6 @@ namespace phase_shifter::level {
Level_ptr _current_level;
std::unordered_map<std::string, std::function<auto(const Tile&, const glm::vec3&)->void>> _spawners;
std::unordered_map<char, mirrage::renderer::Model_ptr> _tile_models;
};
} // namespace phase_shifter::level
......@@ -133,6 +133,7 @@ namespace phase_shifter {
_hud_system->update(dt);
_model_loading->update(dt);
_level_system->draw(*_renderer);
_renderer->update(dt * _beat_system->graphic_time_scale());
_sound_manager->update(dt);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment