diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-17 13:28:37 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-17 13:28:37 +0200 |
commit | 7f01dc47b0fd322d8c2b3f27eb1a94cd450a26a5 (patch) | |
tree | ac6201f9179a0315449ad46d742d2db325775eff | |
parent | e65ebe30d3f2af77d57cb15e5e2b30efa454b6a8 (diff) |
a
-rw-r--r-- | main/app.cpp | 23 | ||||
-rw-r--r-- | main/app.hpp | 28 | ||||
-rw-r--r-- | main/draw.cpp | 79 | ||||
-rw-r--r-- | main/editor.cpp | 7 | ||||
-rw-r--r-- | main/editor.hpp | 3 | ||||
-rw-r--r-- | main/update.cpp | 23 | ||||
-rw-r--r-- | src/chunk.cpp | 6 | ||||
-rw-r--r-- | src/chunk.hpp | 1 | ||||
-rw-r--r-- | src/global-coords.cpp | 9 | ||||
-rw-r--r-- | src/global-coords.hpp | 26 | ||||
-rw-r--r-- | src/world.cpp | 31 | ||||
-rw-r--r-- | src/world.hpp | 33 |
12 files changed, 160 insertions, 109 deletions
diff --git a/main/app.cpp b/main/app.cpp index b412c81b..4150e452 100644 --- a/main/app.cpp +++ b/main/app.cpp @@ -30,6 +30,10 @@ app::app(const Arguments& arguments): _imgui = ImGuiIntegration::Context(Vector2{windowSize()}, windowSize(), framebufferSize()); setup_menu(); SDL_MaximizeWindow(window()); + { + auto c = _world[chunk_coords{0, 0}]; + make_test_chunk(*c); + } timeline.start(); } @@ -130,3 +134,22 @@ void app::event_mouse_enter() } } // namespace floormat + +MAGNUM_APPLICATION_MAIN(floormat::app) + +#ifdef _MSC_VER +#include <cstdlib> // for __arg{c,v} +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmain" +#endif +extern "C" int __stdcall WinMain(void*, void*, void*, int); + +extern "C" int __stdcall WinMain(void*, void*, void*, int) +{ + return main(__argc, __argv); +} +#ifdef __clang__ +# pragma clang diagnostic pop +#endif +#endif diff --git a/main/app.hpp b/main/app.hpp index 403b8888..1237f205 100644 --- a/main/app.hpp +++ b/main/app.hpp @@ -10,6 +10,7 @@ #include "draw/wireframe-box.hpp" #include "compat/enum-bitset.hpp" #include "editor.hpp" +#include "world.hpp" #include <Magnum/Timeline.h> #include <Magnum/Platform/Sdl2Application.h> #include <Magnum/GL/DebugOutput.h> @@ -25,10 +26,14 @@ struct app final : Platform::Application explicit app(const Arguments& arguments); virtual ~app(); - void drawEvent() override; + void update(float dt); - void do_camera(float dt); + void reset_camera_offset(); + void update_window_scale(Vector2i window_size); + + void do_camera(float dt); + void do_key(KeyEvent::Key k, KeyEvent::Modifiers m, bool pressed, bool repeated); void keyPressEvent(KeyEvent& event) override; void keyReleaseEvent(KeyEvent& event) override; @@ -37,29 +42,30 @@ struct app final : Platform::Application void mouseMoveEvent(MouseMoveEvent& event) override; void mouseScrollEvent(MouseScrollEvent& event) override; void textInputEvent(TextInputEvent& event) override; + void viewportEvent(ViewportEvent& event) override; void anyEvent(SDL_Event& event) override; void event_leave(); void event_enter(); void event_mouse_enter(); void event_mouse_leave(); - void do_key(KeyEvent::Key k, KeyEvent::Modifiers m, bool pressed, bool repeated); - void draw_chunk(chunk& c); - void draw_wireframe_quad(local_coords pt); + void drawEvent() override; + void draw_world(); + void draw_wireframe_quad(global_coords pt); void draw_wireframe_box(local_coords pt); - void update_window_scale(Vector2i window_size); - void viewportEvent(ViewportEvent& event) override; + void do_menu(); void draw_menu_(tile_type& type, float main_menu_height); void setup_menu(); void display_menu(); + void debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id, GL::DebugOutput::Severity severity, const std::string& str) const; void* register_debug_callback(); - Vector2 pixel_to_tile(Vector2 position) const; + global_coords pixel_to_tile(Vector2 position) const; void draw_cursor_tile(); - void do_mouse_click(Vector2 pos, int button); + void do_mouse_click(global_coords pos, int button); std::optional<Vector2i> _cursor_pos; @@ -71,7 +77,7 @@ struct app final : Platform::Application quit, MAX }; - chunk make_test_chunk(); + void make_test_chunk(chunk& c); const void* _dummy = register_debug_callback(); tile_shader _shader; @@ -79,7 +85,6 @@ struct app final : Platform::Application tile_atlas_ floor2 = loader.tile_atlas("metal1.tga", {2, 2}); tile_atlas_ wall1 = loader.tile_atlas("wood2.tga", {2, 2}); tile_atlas_ wall2 = loader.tile_atlas("wood1.tga", {2, 2}); - chunk _chunk = make_test_chunk(); floor_mesh _floor_mesh; wall_mesh _wall_mesh; @@ -88,6 +93,7 @@ struct app final : Platform::Application ImGuiIntegration::Context _imgui{NoCreate}; + world _world; Vector2 camera_offset; enum_bitset<key> keys; Magnum::Timeline timeline; diff --git a/main/draw.cpp b/main/draw.cpp index 91277c34..fde48915 100644 --- a/main/draw.cpp +++ b/main/draw.cpp @@ -25,7 +25,7 @@ void app::drawEvent() { } _shader.set_tint({1, 1, 1, 1}); - draw_chunk(_chunk); + draw_world(); draw_cursor_tile(); display_menu(); @@ -34,16 +34,17 @@ void app::drawEvent() { timeline.nextFrame(); } -void app::draw_chunk(chunk& c) +void app::draw_world() { + // TODO chunk offset + std::int16_t minx = 0, maxx = 0, miny = 0, maxy = 0; { - int minx = 0, maxx = 0, miny = 0, maxy = 0; - auto fn = [&](int x, int y) { - const auto pos = pixel_to_tile({(float)x, (float)y}) / Vector2{TILE_MAX_DIM, TILE_MAX_DIM}; - minx = std::min(minx, (int)std::floor(pos[0])); - maxx = std::max(maxx, (int)(pos[0])); - miny = std::min(miny, (int)std::floor(pos[1])); - maxy = std::max(maxy, (int)(pos[1])); + const auto fn = [&](int x, int y) { + const auto pos = pixel_to_tile({(float)x, (float)y}).chunk(); + minx = std::min(minx, pos.x); + maxx = std::max(maxx, pos.x); + miny = std::min(miny, pos.y); + maxy = std::max(maxy, pos.y); }; const auto sz = windowSize(); const auto x = sz[0], y = sz[1]; @@ -51,22 +52,49 @@ void app::draw_chunk(chunk& c) fn(x, 0); fn(0, y); fn(x, y); - - // TODO - printf(""); // put breakpoint here } + const auto old_camera_offset = _shader.camera_offset(); _shader.set_tint({1, 1, 1, 1}); - _floor_mesh.draw(_shader, c); - _wall_mesh.draw(_shader, c); + + for (std::int16_t y = miny; y <= maxy; y++) + for (std::int16_t x = minx; x <= maxx; x++) + { + const auto offset = project({float(x)*TILE_MAX_DIM*TILE_SIZE[0], + float(y)*TILE_MAX_DIM*TILE_SIZE[1], + 0}); + _shader.set_camera_offset(offset + old_camera_offset); + auto c = _world[chunk_coords{x, y}]; + _floor_mesh.draw(_shader, *c); + } + + for (std::int16_t y = miny; y <= maxy; y++) + for (std::int16_t x = minx; x <= maxx; x++) + { + const auto offset = project({float(x)*TILE_MAX_DIM*TILE_SIZE[0], + float(y)*TILE_MAX_DIM*TILE_SIZE[1], + 0}); + _shader.set_camera_offset(offset + old_camera_offset); + auto c = _world[chunk_coords{x, y}]; + _wall_mesh.draw(_shader, *c); + } + + _shader.set_camera_offset(old_camera_offset); } -void app::draw_wireframe_quad(local_coords pt) +void app::draw_wireframe_quad(global_coords pos) { constexpr float LINE_WIDTH = 1; + { + const auto c = _world[pos.chunk()]; + if (const auto& tile = (*c)[pos.local()]; !tile.ground_image) + return; + } + + const auto pt = pos.to_signed(); constexpr auto X = TILE_SIZE[0], Y = TILE_SIZE[1]; - const Vector3 center {X*pt.x, Y*pt.y, 0}; + const Vector3 center {X*pt[0], Y*pt[1], 0}; _shader.set_tint({1, 0, 0, 1}); _wireframe_quad.draw(_shader, {center, {TILE_SIZE[0], TILE_SIZE[1]}, LINE_WIDTH}); } @@ -83,22 +111,3 @@ void app::draw_wireframe_box(local_coords pt) } } // namespace floormat - -MAGNUM_APPLICATION_MAIN(floormat::app) - -#ifdef _MSC_VER -#include <cstdlib> // for __arg{c,v} -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wmain" -#endif -extern "C" int __stdcall WinMain(void*, void*, void*, int); - -extern "C" int __stdcall WinMain(void*, void*, void*, int) -{ - return main(__argc, __argv); -} -#ifdef __clang__ -# pragma clang diagnostic pop -#endif -#endif diff --git a/main/editor.cpp b/main/editor.cpp index e95bc6e3..04578adb 100644 --- a/main/editor.cpp +++ b/main/editor.cpp @@ -126,14 +126,11 @@ editor::editor() { } -void editor::click_at_tile(Vector2 pos, int mouse_button) +void editor::click_at_tile(const global_coords pos, int mouse_button) { if (mouse_button == 0) { - if (pos[0] >= 0 && pos[1] >= 0 && pos[0] < TILE_MAX_DIM && pos[1] < TILE_MAX_DIM) - { - - } + // TODO } } diff --git a/main/editor.hpp b/main/editor.hpp index aac474c0..f9e2def7 100644 --- a/main/editor.hpp +++ b/main/editor.hpp @@ -1,6 +1,7 @@ #pragma once #include "compat/defs.hpp" #include "tile-atlas.hpp" +#include "global-coords.hpp" #include <cstdint> #include <map> #include <memory> @@ -66,7 +67,7 @@ struct editor final tile_type& floor() { return _floor; } const tile_type& floor() const { return _floor; } - void click_at_tile(Vector2 pos, int mouse_button); + void click_at_tile(global_coords pos, int mouse_button); editor(); editor(editor&&) noexcept = default; diff --git a/main/update.cpp b/main/update.cpp index 1c7bb500..28e1d985 100644 --- a/main/update.cpp +++ b/main/update.cpp @@ -2,10 +2,9 @@ namespace floormat { -chunk app::make_test_chunk() +void app::make_test_chunk(chunk& c) { constexpr auto N = TILE_MAX_DIM; - chunk c; for (auto [x, k, pt] : c) { const auto& atlas = pt.x > N/2 && pt.y >= N/2 ? floor2 : floor1; x.ground_image = { atlas, (std::uint8_t)(k % atlas->num_tiles().product()) }; @@ -15,10 +14,9 @@ chunk app::make_test_chunk() c[{K, K }].wall_west = { wall2, 0 }; c[{K, K+1}].wall_north = { wall1, 0 }; c[{K+1, K }].wall_west = { wall2, 0 }; - return c; } -void app::do_mouse_click(const Vector2 pos, int button) +void app::do_mouse_click(const global_coords pos, int button) { _editor.click_at_tile(pos, button); } @@ -31,23 +29,18 @@ void app::update(float dt) Platform::Sdl2Application::exit(0); } -Vector2 app::pixel_to_tile(Vector2 position) const +global_coords app::pixel_to_tile(Vector2 position) const { - const auto px = position - Vector2{windowSize()}*.5f - camera_offset; - return unproject(px) / Vector2{TILE_SIZE[0]*.5f, TILE_SIZE[1]*.5f} + Vector2{.5f, .5f}; + const Vector2 px = position - Vector2{windowSize()}*.5f - camera_offset; + const Vector2 vec = unproject(px) / Vector2{TILE_SIZE[0]*.5f, TILE_SIZE[1]*.5f} + Vector2{.5f, .5f}; + const auto x = (std::int32_t)std::floor(vec[0]), y = (std::int32_t)std::floor(vec[1]); + return { x, y }; } void app::draw_cursor_tile() { if (_cursor_pos) - { - const auto tile = pixel_to_tile(Vector2(*_cursor_pos)); - if (std::min(tile[0], tile[1]) >= 0 && std::max(tile[0], tile[1]) < (int)TILE_MAX_DIM) - { - const auto x = std::uint8_t(tile[0]), y = std::uint8_t(tile[1]); - draw_wireframe_quad({x, y}); - } - } + draw_wireframe_quad(pixel_to_tile(Vector2(*_cursor_pos))); } } // namespace floormat diff --git a/src/chunk.cpp b/src/chunk.cpp index 95904d81..d8c2d011 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -4,9 +4,15 @@ namespace floormat { bool chunk::empty() const { + if (!_maybe_empty) + return false; + for (const tile& x : _tiles) if (x.ground_image || x.wall_north || x.wall_west) + { + _maybe_empty = false; return false; + } return true; } diff --git a/src/chunk.hpp b/src/chunk.hpp index 7ef0bc94..9e41c5fb 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -41,6 +41,7 @@ struct chunk final private: std::array<tile, TILE_COUNT> _tiles = {}; + mutable bool _maybe_empty = true; }; } // namespace floormat diff --git a/src/global-coords.cpp b/src/global-coords.cpp index 997f1c11..e10e921f 100644 --- a/src/global-coords.cpp +++ b/src/global-coords.cpp @@ -9,9 +9,10 @@ static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>); -static_assert(global_coords{{-1, -1}, {2, 3}} == global_coords{((-1 + (1 << 15)) << 4) + 2, ((-1 + (1 << 15)) << 4) + 3}); -static_assert(global_coords{15, 15}.chunk() == global_coords{}.chunk()); -static_assert(global_coords{15, 16}.chunk() != global_coords{}.chunk()); -static_assert(global_coords{(1 + (1<<15)) << 4 | 3, (2 + (1<<15)) << 4 | 4} == global_coords{{1, 2}, {3, 4}}); +static_assert(TILE_MAX_DIM == (1 << 4)); + +static_assert(global_coords{(int)TILE_MAX_DIM-1, (int)TILE_MAX_DIM-1}.chunk() == global_coords{}.chunk()); +static_assert(global_coords{(int)TILE_MAX_DIM-1, (int)TILE_MAX_DIM}.chunk() != global_coords{}.chunk()); +static_assert(global_coords{(1u + (1<<15)) << 4 | 3, (2u + (1<<15)) << 4 | 4} == global_coords{{1, 2}, {3, 4}}); } // namespace floormat diff --git a/src/global-coords.hpp b/src/global-coords.hpp index e51dc6aa..d3c36c96 100644 --- a/src/global-coords.hpp +++ b/src/global-coords.hpp @@ -1,6 +1,8 @@ #pragma once #include "local-coords.hpp" #include "compat/assert.hpp" +#include <Magnum/Magnum.h> +#include <Magnum/Math/Vector2.h> namespace floormat { @@ -11,31 +13,47 @@ struct chunk_coords final { }; struct global_coords final { - std::uint32_t x = 0, y = 0; + std::uint32_t x = 1 << 15, y = 1 << 15; constexpr global_coords(chunk_coords c, local_coords xy) : x{ std::uint32_t(c.x + (1 << 15)) << 4 | (xy.x & 0x0f) }, y{ std::uint32_t(c.y + (1 << 15)) << 4 | (xy.y & 0x0f) } {} constexpr global_coords(std::uint32_t x, std::uint32_t y) noexcept : x{x}, y{y} {} + constexpr global_coords(std::int32_t x, std::int32_t y) noexcept : + x{std::uint32_t(x + (1 << 15))}, y{std::uint32_t(y + (1 << 15))} + {} constexpr global_coords() noexcept = default; constexpr local_coords local() const noexcept; constexpr chunk_coords chunk() const noexcept; + constexpr Vector2i to_signed() const noexcept; + constexpr bool operator==(const global_coords& other) const noexcept = default; }; constexpr local_coords global_coords::local() const noexcept { - return { (std::uint8_t)(x % TILE_MAX_DIM), (std::uint8_t)(y % TILE_MAX_DIM) }; + return { + std::uint8_t(x & 0x0f), + std::uint8_t(y & 0x0f), + }; } constexpr chunk_coords global_coords::chunk() const noexcept { return { - (std::int16_t)(std::int32_t(x >> 4) - (1 << 15)), - (std::int16_t)(std::int32_t(y >> 4) - (1 << 15)), + std::int16_t((x - (1 << 15)) >> 4), + std::int16_t((y - (1 << 15)) >> 4), + }; +} + +constexpr Vector2i global_coords::to_signed() const noexcept +{ + return { + std::int32_t(x - (1 << 15)), + std::int32_t(y - (1 << 15)), }; } diff --git a/src/world.cpp b/src/world.cpp index 3057fca8..8337bfba 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -5,7 +5,7 @@ namespace floormat { struct chunk_pointer_maker final { - operator std::shared_ptr<chunk>() const { return std::make_shared<chunk>(); } + inline operator std::shared_ptr<chunk>() const { return std::make_shared<chunk>(); } }; world::world() @@ -15,22 +15,26 @@ world::world() std::shared_ptr<chunk> world::operator[](chunk_coords c) noexcept { + maybe_collect(); + + if (_last_chunk) + { + auto& [ret, pos] = *_last_chunk; + if (pos == c) + return ret; + } + auto [it, inserted] = _chunks.try_emplace(c, chunk_pointer_maker{}); - const auto ret = it->second; - return maybe_collect(), ret; + auto ret = it->second; + _last_chunk = { ret, c }; + return ret; } -std::shared_ptr<chunk> world::maybe_chunk(chunk_coords c) noexcept -{ - if (const auto it = _chunks.find(c); it != _chunks.cend()) - return it->second; - else - return nullptr; -} -std::shared_ptr<const chunk> world::maybe_chunk(chunk_coords c) const noexcept +std::tuple<std::shared_ptr<chunk>, tile&> world::operator[](global_coords pt) noexcept { - return const_cast<world&>(*this).maybe_chunk(c); + auto c = operator[](pt.chunk()); + return { c, (*c)[pt.local()] }; } bool world::contains(chunk_coords c) const noexcept @@ -41,6 +45,7 @@ bool world::contains(chunk_coords c) const noexcept void world::clear() { _last_collection = 0; + _last_chunk = std::nullopt; _chunks.clear(); _chunks.rehash(initial_capacity); } @@ -61,7 +66,9 @@ void world::collect() else ++it; } + _last_collection = _chunks.size(); + _last_chunk = std::nullopt; } } // namespace floormat diff --git a/src/world.hpp b/src/world.hpp index 1e8469d9..7c256efc 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -1,24 +1,10 @@ #pragma once #include "compat/int-hash.hpp" #include "global-coords.hpp" +#include "tile.hpp" #include <unordered_map> #include <memory> - -namespace std { - -template<typename> struct hash; - -template<> -struct hash<floormat::chunk_coords> final -{ - constexpr - std::size_t operator()(floormat::chunk_coords c) const noexcept - { - return floormat::int_hash((std::size_t)c.y << 16 | (std::size_t)c.x); - } -}; - -} // namespace std +#include <optional> namespace floormat { @@ -28,20 +14,23 @@ struct world final { world(); std::shared_ptr<chunk> operator[](chunk_coords c) noexcept; - std::shared_ptr<chunk> maybe_chunk(chunk_coords c) noexcept; - std::shared_ptr<const chunk> maybe_chunk(chunk_coords c) const noexcept; + std::tuple<std::shared_ptr<chunk>, tile&> operator[](global_coords pt) noexcept; bool contains(chunk_coords c) const noexcept; void clear(); void collect(); private: + void maybe_collect(); + static constexpr std::size_t initial_capacity = 64, collect_every = 32; static constexpr float max_load_factor = .5; - std::size_t _last_collection = 0; + static constexpr auto hasher = [](chunk_coords c) -> std::size_t { + return int_hash((std::size_t)c.y << 16 | (std::size_t)c.x); + }; - void maybe_collect(); - - std::unordered_map<chunk_coords, std::shared_ptr<chunk>> _chunks{initial_capacity}; + std::size_t _last_collection = 0; + mutable std::optional<std::tuple<std::shared_ptr<chunk>, chunk_coords>> _last_chunk; + std::unordered_map<chunk_coords, std::shared_ptr<chunk>, decltype(hasher)> _chunks{initial_capacity, hasher}; }; } // namespace floormat |