diff options
-rw-r--r-- | draw/anim.cpp | 14 | ||||
-rw-r--r-- | main/main-impl.hpp | 2 | ||||
-rw-r--r-- | resources.conf | 6 | ||||
-rw-r--r-- | shaders/lightmap.cpp | 149 | ||||
-rw-r--r-- | shaders/lightmap.frag | 23 | ||||
-rw-r--r-- | shaders/lightmap.hpp | 76 | ||||
-rw-r--r-- | shaders/lightmap.vert | 12 | ||||
-rw-r--r-- | src/chunk-collision.cpp | 36 | ||||
-rw-r--r-- | src/chunk.hpp | 14 | ||||
-rw-r--r-- | src/tile-bbox.hpp | 46 | ||||
-rw-r--r-- | userconfig-sthalik@Windows-GNU.cmake | 2 |
11 files changed, 282 insertions, 98 deletions
diff --git a/draw/anim.cpp b/draw/anim.cpp index 03f6df76..254661e5 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -63,14 +63,6 @@ void anim_mesh::draw(tile_shader& shader, const Vector2i& win_size, chunk& c, st GL::MeshView mesh{mesh_}; const auto max_index = uint32_t(size*quad_index_count - 1); - constexpr auto do_draw = [](tile_shader& shader, GL::Mesh& mesh_, anim_atlas* atlas, uint32_t i, uint32_t max_index) { - GL::MeshView mesh{mesh_}; - atlas->texture().bind(0); - mesh.setCount((int)(quad_index_count * 1)); - mesh.setIndexRange((int)(i*quad_index_count), 0, max_index); - shader.draw(mesh); - }; - uint32_t i = 0; for (const auto& x : es) @@ -84,7 +76,11 @@ void anim_mesh::draw(tile_shader& shader, const Vector2i& win_size, chunk& c, st if (!e.is_dynamic()) { fm_assert(i < size); - do_draw(shader, mesh_, &atlas, x.mesh_idx, max_index); + GL::MeshView mesh{mesh_}; + atlas.texture().bind(0); + mesh.setCount((int)(quad_index_count * 1)); + mesh.setIndexRange((int)(i*quad_index_count), 0, max_index); + shader.draw(mesh); i++; } else diff --git a/main/main-impl.hpp b/main/main-impl.hpp index 3a3e4c7b..f5dc5010 100644 --- a/main/main-impl.hpp +++ b/main/main-impl.hpp @@ -6,6 +6,7 @@ #include "draw/wall.hpp" #include "draw/anim.hpp" #include "shaders/shader.hpp" +#include "shaders/lightmap.hpp" #include "main/clickable.hpp" #include <vector> #include <Corrade/Containers/String.h> @@ -95,6 +96,7 @@ private: [[maybe_unused]] char _dummy = (register_debug_callback(), '\0'); floormat_app& app; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) tile_shader _shader; + lightmap_shader _lightmap_shader; std::vector<clickable> _clickable_scenery; struct world _world{}; Magnum::Timeline timeline; diff --git a/resources.conf b/resources.conf index 2cde441c..cdd59355 100644 --- a/resources.conf +++ b/resources.conf @@ -5,3 +5,9 @@ filename=shaders/shader.frag [file] filename=shaders/shader.vert + +[file] +filename=shaders/lightmap.frag + +[file] +filename=shaders/lightmap.vert diff --git a/shaders/lightmap.cpp b/shaders/lightmap.cpp index 3575e424..8e8e1884 100644 --- a/shaders/lightmap.cpp +++ b/shaders/lightmap.cpp @@ -1,20 +1,153 @@ -#include "lightmap.hpp" -#include "src/local-coords.hpp" +#include "shaders/lightmap.hpp" +#include "compat/assert.hpp" +#include "src/tile-defs.hpp" +#include "loader/loader.hpp" +#include <Corrade/Containers/Iterable.h> +#include <Magnum/Magnum.h> +#include <Magnum/GL/MeshView.h> +#include <Magnum/GL/Shader.h> +#include <Magnum/GL/Version.h> +//#include "src/tile-bbox.hpp" -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wfloat-equal" +#if defined __CLION_IDE__ || defined __clang__ +#pragma GCC diagnostic ignored "-Wfloat-equal" #endif namespace floormat { -lightmap_shader::~lightmap_shader() = default; -bool lightmap_shader::light_s::operator==(const light_s&) const noexcept = default; +namespace { + +constexpr auto chunk_size = TILE_SIZE2 * TILE_MAX_DIM; +constexpr auto chunk_offset = TILE_SIZE2/2; +constexpr auto image_size = iTILE_SIZE2 * TILE_MAX_DIM; +constexpr auto buffer_size = 256uz; -static constexpr Vector2 output_size = TILE_MAX_DIM * TILE_SIZE2 * 3; +} // namespace -lightmap_shader::lightmap_shader() +auto lightmap_shader::make_framebuffer() -> Framebuffer { + Framebuffer framebuffer; + + framebuffer.fb = GL::Framebuffer{{ {}, image_size }}; + + framebuffer.color = GL::Texture2D{}; + framebuffer.color.setStorage(1, GL::TextureFormat::RGBA8, image_size); + //framebuffer.depth = GL::Renderbuffer{}; + //framebuffer.depth.setStorage(GL::RenderbufferFormat::DepthComponent32F, fb_size); + + framebuffer.fb.attachTexture(GL::Framebuffer::ColorAttachment{0}, framebuffer.color, 0); + //framebuffer.fb.attachRenderbuffer(GL::Framebuffer::BufferAttachment::Depth, framebuffer.depth); + framebuffer.fb.clearColor(0, Color4{0.f, 0.f, 0.f, 1.f}); + //framebuffer.fb.clearDepth(0); + + return framebuffer; +} +GL::Mesh lightmap_shader::make_mesh() +{ + GL::Mesh mesh{GL::MeshPrimitive::Triangles}; + mesh.addVertexBuffer(_vertex_buf, 0, Position{}) + .setIndexBuffer(_index_buf, 0, GL::MeshIndexType::UnsignedShort) + .setCount(int32_t(6 * buffer_size)); + return mesh; } +lightmap_shader::lightmap_shader() : + framebuffer { make_framebuffer() }, + _quads { ValueInit, buffer_size }, + _indexes { ValueInit, buffer_size }, + _vertex_buf { _quads }, + _index_buf { _indexes }, + _mesh { make_mesh() } +{ + constexpr auto min_version = GL::Version::GL330; + const auto version = GL::Context::current().version(); + + if (version < min_version) + fm_abort("floormat requires OpenGL version %d, only %d is supported", (int)min_version, (int)version); + + GL::Shader vert{version, GL::Shader::Type::Vertex}; + GL::Shader frag{version, GL::Shader::Type::Fragment}; + + vert.addSource(loader.shader("shaders/lightmap.vert")); + frag.addSource(loader.shader("shaders/lightmap.frag")); + + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShaders({vert, frag}); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); +} + +void lightmap_shader::flush_vertexes() +{ + // todo +} + +void lightmap_shader::clear() +{ + framebuffer.fb.clearColor(0, Color4{1.f, 0.f, 1.f, 1.f}); + //framebuffer.fb.clearDepth(0); +} + +void lightmap_shader::bind() +{ + framebuffer.fb.bind(); +} + +std::array<UnsignedShort, 6> lightmap_shader::quad_indexes(size_t N) +{ + using u16 = UnsignedShort; + return { /* 3--1 1 */ + (u16)(0+N*4), (u16)(1+N*4), (u16)(2+N*4), /* | / /| */ + (u16)(2+N*4), (u16)(1+N*4), (u16)(3+N*4), /* |/ / | */ + }; /* 2 2--0 */ +} + +void lightmap_shader::add_light(Vector2i neighbor_offset, const light_s& light) +{ + fm_debug_assert(_count == 0); + + constexpr auto tile_size = TILE_SIZE2.sum()/2; + constexpr auto scale = 2/chunk_size; + auto dist = std::fmax(0.f, light.dist * tile_size); + auto center = light.center + chunk_offset + Vector2(neighbor_offset)*chunk_size; + auto center_clip = Vector2{center} * scale; // clip coordinate + constexpr auto image_size_factor = Vector2(image_size) / Vector2(chunk_size); + auto center_fragcoord = center * image_size_factor; // window-relative coordinates + + _indexes[0] = quad_indexes(0); + _quads[0] = std::array<Vector2, 4>{{ + { dist + center_clip.x(), -dist + center_clip.y() }, + { dist + center_clip.x(), dist + center_clip.y() }, + { -dist + center_clip.x(), -dist + center_clip.y() }, + { -dist + center_clip.x(), dist + center_clip.y() }, + }}; + + _index_buf.setSubData(0, ArrayView<std::array<UnsignedShort, 6>>{_indexes, 1}); + _vertex_buf.setSubData(0, ArrayView<std::array<Vector2, 4>>{_quads, 1}); + + setUniform(ColorIntensityUniform, Vector4{Vector3{light.color}, dist}); + setUniform(CenterUniform, center_fragcoord); + setUniform(FalloffUniform, (uint32_t)light.falloff); + setUniform(SizeUniform, chunk_size); + + +} + +lightmap_shader::~lightmap_shader() = default; + +void lightmap_shader::begin(Vector2i neighbor_offset, const light_s& light) +{ + fm_assert(_count == 0); + clear(); + add_light(neighbor_offset, light); +} + +void lightmap_shader::end() +{ + flush_vertexes(); +} + +bool light_s::operator==(const light_s&) const noexcept = default; + } // namespace floormat diff --git a/shaders/lightmap.frag b/shaders/lightmap.frag index 2179160c..8690ffcb 100644 --- a/shaders/lightmap.frag +++ b/shaders/lightmap.frag @@ -1,18 +1,13 @@ precision mediump float; -struct light_u -{ - vec4 color_and_intensity; - vec2 center; - uint mode; -}; - -#define TILE_MAX_DIM 16 -#define TILE_SIZE_X 64 -#define TILE_SIZE_Y 64 +layout (location = 0) uniform vec4 color_intensity; +layout (location = 1) uniform vec2 center; +layout (location = 2) uniform uint falloff; +layout (location = 3) uniform vec2 size; -#define CHUNK_SIZE_X (TILE_SIZE_X * TILE_MAX_DIM) -#define CHUNK_SIZE_Y (TILE_SIZE_Y * TILE_MAX_DIM) +out vec4 color; -layout (location = 0) uniform vec4 color_intensity; -layout (location = 1) uniform vec2 px; +void main() { + vec3 color = color_intensity.xyz; + float dist = color_intensity.w; +} diff --git a/shaders/lightmap.hpp b/shaders/lightmap.hpp index a2d566e6..a7204723 100644 --- a/shaders/lightmap.hpp +++ b/shaders/lightmap.hpp @@ -1,15 +1,32 @@ #pragma once #include "light-falloff.hpp" -#include <Magnum/GL/AbstractShaderProgram.h> +#include <array> +#include <Corrade/Containers/Array.h> #include <Magnum/Math/Vector2.h> -#include <Magnum/Math/Vector3.h> #include <Magnum/Math/Vector4.h> #include <Magnum/Math/Color.h> +#include <Magnum/GL/AbstractShaderProgram.h> +#include <Magnum/GL/Buffer.h> +#include <Magnum/GL/Framebuffer.h> +#include <Magnum/GL/Mesh.h> +//#include <Magnum/GL/Renderbuffer.h> +#include <Magnum/GL/Texture.h> namespace floormat { -struct local_coords; +struct light_s final +{ + Vector2 center; + float dist = 1; + //float depth = -1 + 1e-4f; + Math::Color3<uint8_t> color {255, 255, 255}; + light_falloff falloff = light_falloff::linear; + + bool operator==(const light_s&) const noexcept; +}; + +struct chunk; struct lightmap_shader final : GL::AbstractShaderProgram { @@ -18,32 +35,43 @@ struct lightmap_shader final : GL::AbstractShaderProgram explicit lightmap_shader(); ~lightmap_shader() override; - void set_light(Vector2i neighbor_offset, local_coords pos, Vector2b offset); - struct light light() const; // is a reader accessor needed? - -private: - static Vector2i get_px_pos(Vector2i neighbor_offset, local_coords pos, Vector2b offset); - - struct light_u final - { - Vector4 color_and_intensity; - Vector2 center; - uint32_t mode; + struct Framebuffer final { + GL::Framebuffer fb{NoCreate}; + //GL::Renderbuffer depth{NoCreate}; + GL::Texture2D color{NoCreate}; }; - struct light_s final - { - float intensity = 1; - Color3ub color {255, 255, 255}; - Vector2i center; - light_falloff falloff; + void begin(Vector2i neighbor_offset, const light_s& light); + void add_chunk(Vector2i neighbor_offset, const chunk& ch); + void add_vertex(Vector2i neighbor_offset, const std::array<Vector2, 4>& obj); + void end(); + GL::Texture2D& texture(); - bool operator==(const light_s&) const noexcept; - }; +private: + static Framebuffer make_framebuffer(); + GL::Mesh make_mesh(); + void add_light(Vector2i neighbor_offset, const light_s& light); + void flush_vertexes(); + void bind(); + void clear(); + static std::array<UnsignedShort, 6> quad_indexes(size_t N); - enum { ColorUniform = 0, CenterUniform = 1, FalloffUniform = 2, DepthUniform = 3, }; + enum : int { + ColorIntensityUniform = 0, + CenterUniform = 1, + FalloffUniform = 2, + SizeUniform = 3, + //DepthUniform = 4, + }; - light_s _light; + Framebuffer framebuffer; + Array<std::array<Vector2, 4>> _quads; + Array<std::array<UnsignedShort, 6>> _indexes; + size_t _count = 0; + //light_u _light_uniform; + //light_s _light; + GL::Buffer _vertex_buf{NoCreate}, _index_buf{NoCreate}; + GL::Mesh _mesh{NoCreate}; }; } // namespace floormat diff --git a/shaders/lightmap.vert b/shaders/lightmap.vert index e69de29b..a044a141 100644 --- a/shaders/lightmap.vert +++ b/shaders/lightmap.vert @@ -0,0 +1,12 @@ +precision mediump float; + +layout (location = 0) uniform vec4 color_intensity; +layout (location = 1) uniform vec2 center; +layout (location = 2) uniform uint falloff; +layout (location = 3) uniform vec2 size; + +layout (location = 0) in vec4 position; + +void main() { + gl_Position = vec4(position.x, -position.y, 0, 1); +} diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp index 49b7bc7d..7cf436a0 100644 --- a/src/chunk-collision.cpp +++ b/src/chunk-collision.cpp @@ -3,6 +3,7 @@ #include "entity.hpp" #include "src/RTree-search.hpp" #include "src/chunk-scenery.hpp" +#include "src/tile-bbox.hpp" #include <bit> #include <Corrade/Containers/PairStl.h> @@ -12,41 +13,6 @@ chunk::RTree* chunk::rtree() noexcept { ensure_passability(); return &_rtree; } namespace { -constexpr float wall_depth = 8, wall_depth_2 = wall_depth*.5f; - -constexpr Vector2 tile_start(size_t k) -{ - constexpr auto half_tile = Vector2(TILE_SIZE2)/2; - const local_coords coord{k}; - return TILE_SIZE2 * Vector2(coord) - half_tile; -} - -Pair<Vector2i, Vector2i> scenery_tile(local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) -{ - auto center = iTILE_SIZE2 * Vector2i(local) + Vector2i(offset) + Vector2i(bbox_offset); - auto min = center - Vector2i(bbox_size/2); - auto size = Vector2i(bbox_size); - return { min, min + size, }; -} - -constexpr Pair<Vector2, Vector2> whole_tile(size_t k) -{ - auto min = tile_start(k); - return { min, min + TILE_SIZE2, }; -} - -constexpr Pair<Vector2, Vector2> wall_north(size_t k) -{ - auto min = tile_start(k) - Vector2(0, wall_depth_2); - return { min, min + Vector2(TILE_SIZE2[0], wall_depth), }; -} - -constexpr Pair<Vector2, Vector2> wall_west(size_t k) -{ - auto min = tile_start(k) - Vector2(wall_depth_2, 0); - return { min, min + Vector2(wall_depth, TILE_SIZE2[1]), }; -} - constexpr object_id make_id(collision_type type, pass_mode p, object_id id) { return std::bit_cast<object_id>(collision_data { (object_id)type, (object_id)p, id }); diff --git a/src/chunk.hpp b/src/chunk.hpp index 8453bf83..505e335d 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -128,13 +128,13 @@ private: RTree _rtree; - mutable bool _maybe_empty : 1 = true, - _ground_modified : 1 = true, - _walls_modified : 1 = true, - _scenery_modified : 1 = true, - _pass_modified : 1 = true, - _teardown : 1 = false, - _entities_sorted : 1 = true; + mutable bool _maybe_empty : 1 = true, + _ground_modified : 1 = true, + _walls_modified : 1 = true, + _scenery_modified : 1 = true, + _pass_modified : 1 = true, + _teardown : 1 = false, + _entities_sorted : 1 = true; void ensure_scenery_buffers(scenery_scratch_buffers bufs); static topo_sort_data make_topo_sort_data(entity& e, uint32_t mesh_idx); diff --git a/src/tile-bbox.hpp b/src/tile-bbox.hpp new file mode 100644 index 00000000..3275e22a --- /dev/null +++ b/src/tile-bbox.hpp @@ -0,0 +1,46 @@ +#pragma once +#include "src/tile-defs.hpp" +#include "src/local-coords.hpp" +#include <Magnum/Magnum.h> +#include <Magnum/Math/Vector2.h> + +namespace floormat { + +namespace { +constexpr float wall_depth = 8, wall_depth_2 = wall_depth*.5f; +} // namespace + +constexpr Vector2 tile_start(size_t k) +{ + constexpr auto half_tile = Vector2(TILE_SIZE2)/2; + const local_coords coord{k}; + return TILE_SIZE2 * Vector2(coord) - half_tile; +} + +constexpr Pair<Vector2i, Vector2i> scenery_tile(local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) +{ + auto center = iTILE_SIZE2 * Vector2i(local) + Vector2i(offset) + Vector2i(bbox_offset); + auto min = center - Vector2i(bbox_size/2); + auto size = Vector2i(bbox_size); + return { min, min + size, }; +} + +constexpr Pair<Vector2, Vector2> whole_tile(size_t k) +{ + auto min = tile_start(k); + return { min, min + TILE_SIZE2, }; +} + +constexpr Pair<Vector2, Vector2> wall_north(size_t k) +{ + auto min = tile_start(k) - Vector2(0, wall_depth_2); + return { min, min + Vector2(TILE_SIZE2[0], wall_depth), }; +} + +constexpr Pair<Vector2, Vector2> wall_west(size_t k) +{ + auto min = tile_start(k) - Vector2(wall_depth_2, 0); + return { min, min + Vector2(wall_depth, TILE_SIZE2[1]), }; +} + +} // namespace floormat diff --git a/userconfig-sthalik@Windows-GNU.cmake b/userconfig-sthalik@Windows-GNU.cmake index 5f9766f4..7b7759ae 100644 --- a/userconfig-sthalik@Windows-GNU.cmake +++ b/userconfig-sthalik@Windows-GNU.cmake @@ -63,7 +63,7 @@ endfunction() function(fm-userconfig-src) add_compile_options( -Wall -Wextra -Wpedantic -Wno-old-style-cast -Wno-padded - -fconcepts-diagnostics-depth=2 + #-fconcepts-diagnostics-depth=2 ) add_link_options(-Wno-lto-type-mismatch -Wno-odr) add_compile_options( |