summaryrefslogtreecommitdiffhomepage
path: root/main
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-10-23 17:31:31 +0200
committerStanislaw Halik <sthalik@misaki.pl>2022-10-23 17:31:31 +0200
commitcce1f768e7399b838a2b865511915bdd576dbbf4 (patch)
tree4c6a8f2dc9112394fd329d56c0f628ce66b16467 /main
parent6b875a0919b9932eca9ed877552c34ecb220b7d8 (diff)
a
Diffstat (limited to 'main')
-rw-r--r--main/CMakeLists.txt16
-rw-r--r--main/camera.cpp88
-rw-r--r--main/debug.cpp10
-rw-r--r--main/draw.cpp14
-rw-r--r--main/editor.cpp234
-rw-r--r--main/editor.hpp93
-rw-r--r--main/events.cpp35
-rw-r--r--main/floormat-app.cpp8
-rw-r--r--main/floormat-app.hpp44
-rw-r--r--main/floormat-events.cpp100
-rw-r--r--main/floormat-main-impl.cpp106
-rw-r--r--main/floormat-main-impl.hpp66
-rw-r--r--main/floormat-main.hpp35
-rw-r--r--main/floormat.hpp30
-rw-r--r--main/imgui-raii.hpp86
-rw-r--r--main/imgui.cpp240
-rw-r--r--main/keyboard.cpp38
-rw-r--r--main/loader-impl.cpp149
-rw-r--r--main/main.cpp (renamed from main/app.cpp)14
-rw-r--r--main/main.hpp (renamed from main/app.hpp)14
-rw-r--r--main/update.cpp55
21 files changed, 431 insertions, 1044 deletions
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index e567dee2..81a67fee 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -1,22 +1,12 @@
-set(self "${PROJECT_NAME}-main")
file(GLOB sources "*.cpp" CONFIGURE_ARGS)
link_libraries(${PROJECT_NAME})
link_libraries(Magnum::Sdl2Application Magnum::Trade)
link_libraries(MagnumIntegration::ImGui)
-corrade_add_resource(res ../resources.conf)
-if(MSVC)
- set_property(SOURCE "${res}" APPEND PROPERTY COMPILE_OPTIONS "-W0")
-else()
- set_property(SOURCE "${res}" APPEND PROPERTY COMPILE_OPTIONS "-w")
-endif()
-add_library(${self}-lib STATIC "${sources}")
-add_executable(${self} "${res}")
-target_link_libraries(${self} ${self}-lib)
-set_property(TARGET ${self} PROPERTY OUTPUT_NAME "${PROJECT_NAME}")
-install(TARGETS ${self} RUNTIME DESTINATION bin)
+add_library(${PROJECT_NAME}-main STATIC "${sources}")
if(FLOORMAT_PRECOMPILED-HEADERS)
- target_precompile_headers(${self} PRIVATE precomp.hpp)
+ target_precompile_headers(${PROJECT_NAME}-main PRIVATE precomp.hpp)
endif()
+
diff --git a/main/camera.cpp b/main/camera.cpp
deleted file mode 100644
index 7af77211..00000000
--- a/main/camera.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#include "app.hpp"
-#include <Magnum/GL/DefaultFramebuffer.h>
-
-namespace floormat {
-
-void app::do_camera(double dt)
-{
- if (keys[key::camera_reset])
- reset_camera_offset();
- else
- {
- Vector2d dir{};
-
- if (keys[key::camera_up])
- dir += Vector2d{0, -1};
- else if (keys[key::camera_down])
- dir += Vector2d{0, 1};
- if (keys[key::camera_left])
- dir += Vector2d{-1, 0};
- else if (keys[key::camera_right])
- dir += Vector2d{1, 0};
-
- if (dir != Vector2d{})
- {
- constexpr double screens_per_second = 1;
- const auto pixels_per_second = windowSize().length() / screens_per_second;
- auto camera_offset = _shader.camera_offset();
- const auto max_camera_offset = Vector2d(windowSize() * 10);
-
- camera_offset -= dir.normalized() * dt * pixels_per_second;
- camera_offset[0] = std::clamp(camera_offset[0], -max_camera_offset[0], max_camera_offset[0]);
- camera_offset[1] = std::clamp(camera_offset[1], -max_camera_offset[1], max_camera_offset[1]);
-
- _shader.set_camera_offset(camera_offset);
- }
- else
- return;
- }
- recalc_cursor_tile();
- if (_cursor_tile)
- do_mouse_move(*_cursor_tile);
-}
-
-void app::reset_camera_offset()
-{
- _shader.set_camera_offset(tile_shader::project({TILE_MAX_DIM*-.5*dTILE_SIZE[0], TILE_MAX_DIM*-.5*dTILE_SIZE[1], 0}));
- recalc_cursor_tile();
-}
-
-void app::recalc_cursor_tile()
-{
- if (_cursor_pixel && !_cursor_in_imgui)
- _cursor_tile = pixel_to_tile(Vector2d(*_cursor_pixel));
- else
- _cursor_tile = std::nullopt;
-}
-
-global_coords app::pixel_to_tile(Vector2d position) const
-{
- constexpr Vector2d pixel_size{dTILE_SIZE[0], dTILE_SIZE[1]};
- constexpr Vector2d half{.5, .5};
- const Vector2d px = position - Vector2d{windowSize()}*.5 - _shader.camera_offset()*.5;
- const Vector2d vec = tile_shader::unproject(px) / pixel_size + half;
- const auto x = (std::int32_t)std::floor(vec[0]), y = (std::int32_t)std::floor(vec[1]);
- return { x, y };
-}
-
-std::array<std::int16_t, 4> app::get_draw_bounds() const noexcept
-{
-
- using limits = std::numeric_limits<std::int16_t>;
- auto x0 = limits::max(), x1 = limits::min(), y0 = limits::max(), y1 = limits::min();
-
- for (const auto win = Vector2d(windowSize());
- auto p : {pixel_to_tile(Vector2d{0, 0}).chunk(),
- pixel_to_tile(Vector2d{win[0]-1, 0}).chunk(),
- pixel_to_tile(Vector2d{0, win[1]-1}).chunk(),
- pixel_to_tile(Vector2d{win[0]-1, win[1]-1}).chunk()})
- {
- x0 = std::min(x0, p.x);
- x1 = std::max(x1, p.x);
- y0 = std::min(y0, p.y);
- y1 = std::max(y1, p.y);
- }
- return {x0, x1, y0, y1};
-}
-
-} // namespace floormat
diff --git a/main/debug.cpp b/main/debug.cpp
index 3383948b..4ce4a3b0 100644
--- a/main/debug.cpp
+++ b/main/debug.cpp
@@ -1,4 +1,4 @@
-#include "app.hpp"
+#include "main.hpp"
#include <chrono>
#include <Magnum/GL/Renderer.h>
@@ -12,7 +12,7 @@ using GL::Renderer;
using GL::DebugOutput;
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-void app::debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
+void floormat::debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
Severity severity, const std::string& str) const
{
static thread_local auto clock = std::chrono::steady_clock{};
@@ -58,13 +58,13 @@ void app::debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type
std::fputs("", stdout); // put breakpoint here
}
-void app::_debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
+void floormat::_debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
GL::DebugOutput::Severity severity, const std::string& str, const void* self)
{
- static_cast<const app*>(self)->debug_callback(src, type, id, severity, str);
+ static_cast<const floormat*>(self)->debug_callback(src, type, id, severity, str);
}
-void* app::register_debug_callback()
+void* floormat::register_debug_callback()
{
GL::DebugOutput::setCallback(_debug_callback, this);
diff --git a/main/draw.cpp b/main/draw.cpp
index b2e0a637..cc9e85d3 100644
--- a/main/draw.cpp
+++ b/main/draw.cpp
@@ -1,4 +1,4 @@
-#include "app.hpp"
+#include "main.hpp"
#include "tile-defs.hpp"
#include "camera-offset.hpp"
#include <Magnum/GL/DefaultFramebuffer.h>
@@ -8,7 +8,7 @@
namespace floormat {
-void app::drawEvent()
+void floormat::drawEvent()
{
if (const float dt = timeline.previousFrameDuration(); dt > 0)
{
@@ -50,14 +50,14 @@ void app::drawEvent()
timeline.nextFrame();
}
-void app::draw_msaa()
+void floormat::draw_msaa()
{
const with_shifted_camera_offset o{_shader, BASE_X, BASE_Y};
draw_world();
draw_cursor_tile();
}
-void app::draw_world()
+void floormat::draw_world()
{
auto foo = get_draw_bounds();
auto [minx, maxx, miny, maxy] = foo;
@@ -83,7 +83,7 @@ void app::draw_world()
}
}
-void app::draw_wireframe_quad(global_coords pos)
+void floormat::draw_wireframe_quad(global_coords pos)
{
constexpr float LINE_WIDTH = 2;
const auto pt = pos.to_signed();
@@ -96,7 +96,7 @@ void app::draw_wireframe_quad(global_coords pos)
}
}
-void app::draw_wireframe_box(local_coords pt)
+void floormat::draw_wireframe_box(local_coords pt)
{
constexpr float LINE_WIDTH = 1.5;
@@ -107,7 +107,7 @@ void app::draw_wireframe_box(local_coords pt)
_wireframe_box.draw(_shader, {center1, size, LINE_WIDTH});
}
-void app::draw_cursor_tile()
+void floormat::draw_cursor_tile()
{
if (_cursor_tile && !_cursor_in_imgui)
draw_wireframe_quad(*_cursor_tile);
diff --git a/main/editor.cpp b/main/editor.cpp
deleted file mode 100644
index f3c8b157..00000000
--- a/main/editor.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-#include "editor.hpp"
-#include "serialize/json-helper.hpp"
-#include "serialize/tile-atlas.hpp"
-#include "src/loader.hpp"
-#include "random.hpp"
-#include "compat/assert.hpp"
-#include "compat/unreachable.hpp"
-#include "src/tile-defs.hpp"
-#include "src/world.hpp"
-#include <Corrade/Containers/StringStlView.h>
-#include <filesystem>
-#include <vector>
-
-namespace floormat {
-
-static const std::filesystem::path image_path{IMAGE_PATH, std::filesystem::path::generic_format};
-
-tile_type::tile_type(editor_mode mode, Containers::StringView name) : _name{name}, _mode{mode}
-{
- load_atlases();
-}
-
-void tile_type::load_atlases()
-{
- using atlas_array = std::vector<std::shared_ptr<tile_atlas>>;
- for (auto& atlas : json_helper::from_json<atlas_array>(image_path/(_name + ".json")))
- {
- Containers::StringView name = atlas->name();
- if (auto x = name.findLast('.'); x)
- name = name.prefix(x.data());
- auto& [_, vec] = _permutation;
- vec.reserve((std::size_t)atlas->num_tiles());
- _atlases[name] = std::move(atlas);
- }
-}
-
-std::shared_ptr<tile_atlas> tile_type::maybe_atlas(Containers::StringView str)
-{
- auto it = std::find_if(_atlases.begin(), _atlases.end(), [&](const auto& tuple) -> bool {
- const auto& [x, _] = tuple;
- return Containers::StringView{x} == str;
- });
- if (it == _atlases.end())
- return nullptr;
- else
- return it->second;
-}
-
-std::shared_ptr<tile_atlas> tile_type::atlas(Containers::StringView str)
-{
- if (auto ptr = maybe_atlas(str); ptr)
- return ptr;
- else
- fm_abort("no such atlas: %s", str.cbegin());
-}
-
-void tile_type::clear_selection()
-{
- _selected_tile = {};
- _permutation = {};
- _selection_mode = sel_none;
-}
-
-void tile_type::select_tile(const std::shared_ptr<tile_atlas>& atlas, std::size_t variant)
-{
- fm_assert(atlas);
- clear_selection();
- _selection_mode = sel_tile;
- _selected_tile = { atlas, variant % atlas->num_tiles() };
-}
-
-void tile_type::select_tile_permutation(const std::shared_ptr<tile_atlas>& atlas)
-{
- fm_assert(atlas);
- clear_selection();
- _selection_mode = sel_perm;
- _permutation = { atlas, {} };
-}
-
-bool tile_type::is_tile_selected(const std::shared_ptr<const tile_atlas>& atlas, std::size_t variant) const
-{
- return atlas && _selection_mode == sel_tile && _selected_tile &&
- atlas == _selected_tile.atlas && variant == _selected_tile.variant;
-}
-
-bool tile_type::is_permutation_selected(const std::shared_ptr<const tile_atlas>& atlas) const
-{
- const auto& [perm, _] = _permutation;
- return atlas && _selection_mode == sel_perm && perm == atlas;
-}
-
-bool tile_type::is_atlas_selected(const std::shared_ptr<const tile_atlas>& atlas) const
-{
- switch (_selection_mode)
- {
- default:
- case sel_none:
- return false;
- case sel_perm:
- return is_permutation_selected(atlas);
- case sel_tile:
- return atlas && _selected_tile && atlas == _selected_tile.atlas;
- }
-}
-
-template<std::random_access_iterator T>
-void fisher_yates(T begin, T end)
-{
- const auto N = std::distance(begin, end);
- for (auto i = N-1; i >= 1; i--)
- {
- const auto j = random(i+1);
- using std::swap;
- swap(begin[i], begin[j]);
- }
-}
-
-tile_image tile_type::get_selected_perm()
-{
- auto& [atlas, vec] = _permutation;
- const std::size_t N = atlas->num_tiles();
- if (N == 0)
- return {};
- if (vec.empty())
- {
- for (std::size_t i = 0; i < N; i++)
- vec.push_back(i);
- fisher_yates(vec.begin(), vec.end());
- }
- const auto idx = vec.back();
- vec.pop_back();
- return {atlas, idx};
-}
-
-tile_image tile_type::get_selected()
-{
- switch (_selection_mode)
- {
- case sel_none:
- return {};
- case sel_tile:
- return _selected_tile;
- case sel_perm:
- return get_selected_perm();
- default:
- fm_warn_once("invalid editor mode '%u'", (unsigned)_selection_mode);
- break;
- }
-}
-
-void tile_type::place_tile(world& world, global_coords pos, tile_image& img)
-{
- const auto& [c, t] = world[pos];
- const auto& [atlas, variant] = img;
- switch (_mode)
- {
- default:
- fm_warn_once("invalid editor mode '%u'", (unsigned)_mode);
- break;
- case editor_mode::select:
- break;
- case editor_mode::floor: {
- const auto& [c, t] = world[pos];
- t.ground_image = { atlas, variant };
- break;
- }
- case editor_mode::walls: {
- break; // todo
- }
- }
-}
-
-editor::editor()
-{
- set_mode(editor_mode::floor); // TODO
-}
-
-void editor::set_mode(editor_mode mode)
-{
- _mode = mode;
- on_release();
-}
-
-const tile_type* editor::current() const
-{
- switch (_mode)
- {
- case editor_mode::select:
- return nullptr;
- case editor_mode::floor:
- return &_floor;
- case editor_mode::walls:
- return nullptr; // todo
- default:
- fm_warn_once("invalid editor mode '%u'", (unsigned)_mode);
- return nullptr;
- }
-}
-
-tile_type* editor::current()
-{
- return const_cast<tile_type*>(static_cast<const editor&>(*this).current());
-}
-
-void editor::on_release()
-{
- _last_pos = std::nullopt;
-}
-
-void editor::on_mouse_move(world& world, const global_coords pos)
-{
- if (_last_pos && *_last_pos != pos)
- {
- _last_pos = pos;
- on_click(world, pos);
- }
-}
-
-void editor::on_click(world& world, global_coords pos)
-{
- if (auto* mode = current(); mode)
- {
- auto opt = mode->get_selected();
- if (opt)
- {
- _last_pos = pos;
- mode->place_tile(world, pos, opt);
- }
- else
- on_release();
- }
-}
-
-} // namespace floormat
diff --git a/main/editor.hpp b/main/editor.hpp
deleted file mode 100644
index 28ba153c..00000000
--- a/main/editor.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#pragma once
-#include "compat/defs.hpp"
-#include "tile-atlas.hpp"
-#include "global-coords.hpp"
-#include "tile.hpp"
-
-#include <cstdint>
-#include <tuple>
-#include <optional>
-#include <vector>
-#include <map>
-#include <memory>
-#include <Corrade/Containers/StringView.h>
-
-namespace floormat {
-
-enum class editor_mode : unsigned char {
- select, floor, walls,
-};
-
-struct world;
-
-struct tile_type final
-{
- tile_type(editor_mode mode, Containers::StringView name);
- std::shared_ptr<tile_atlas> maybe_atlas(Containers::StringView str);
- std::shared_ptr<tile_atlas> atlas(Containers::StringView str);
- auto cbegin() const { return _atlases.cbegin(); }
- auto cend() const { return _atlases.cend(); }
- auto begin() const { return _atlases.cbegin(); }
- auto end() const { return _atlases.cend(); }
- Containers::StringView name() const { return _name; }
- editor_mode mode() const { return _mode; }
-
- void clear_selection();
- void select_tile(const std::shared_ptr<tile_atlas>& atlas, std::size_t variant);
- void select_tile_permutation(const std::shared_ptr<tile_atlas>& atlas);
- bool is_tile_selected(const std::shared_ptr<const tile_atlas>& atlas, std::size_t variant) const;
- bool is_permutation_selected(const std::shared_ptr<const tile_atlas>& atlas) const;
- bool is_atlas_selected(const std::shared_ptr<const tile_atlas>& atlas) const;
- tile_image get_selected();
- void place_tile(world& world, global_coords pos, tile_image& img);
-
-private:
- enum selection_mode : std::uint8_t {
- sel_none, sel_tile, sel_perm,
- };
- enum rotation : std::uint8_t {
- rot_N, rot_W,
- };
-
- std::string _name;
- std::map<std::string, std::shared_ptr<tile_atlas>> _atlases;
- tile_image _selected_tile;
- std::tuple<std::shared_ptr<tile_atlas>, std::vector<std::size_t>> _permutation;
- selection_mode _selection_mode = sel_none;
- editor_mode _mode;
- rotation _rotation{};
-
- void load_atlases();
- tile_image get_selected_perm();
-};
-
-struct editor final
-{
- [[nodiscard]] bool dirty() const { return _dirty; }
- void set_dirty(bool value) { _dirty = value; }
- [[nodiscard]] editor_mode mode() const { return _mode; }
- void set_mode(editor_mode mode);
-
- tile_type& floor() { return _floor; }
- const tile_type& floor() const { return _floor; }
-
- tile_type* current();
- const tile_type* current() const;
-
- void on_click(world& world, global_coords pos);
- void on_mouse_move(world& world, const global_coords pos);
- void on_release();
-
- editor();
- editor(editor&&) noexcept = default;
- editor& operator=(editor&&) noexcept = default;
- fm_DECLARE_DELETED_COPY_ASSIGNMENT(editor);
-
-private:
- tile_type _floor{editor_mode::floor, "floor"};
- std::optional<global_coords> _last_pos;
- editor_mode _mode = editor_mode::select;
- bool _dirty = false;
-};
-
-} // namespace floormat
diff --git a/main/events.cpp b/main/events.cpp
index 83362bfe..989406ba 100644
--- a/main/events.cpp
+++ b/main/events.cpp
@@ -1,20 +1,18 @@
#pragma once
-#include "app.hpp"
-#include <Magnum/ImGuiIntegration/Context.hpp>
-
+#include "floormat-main.hpp"
#include <cstdio>
#include <SDL_events.h>
#include <SDL_video.h>
namespace floormat {
-void app::viewportEvent(Platform::Sdl2Application::ViewportEvent& event)
+void main_impl::viewportEvent(Platform::Sdl2Application::ViewportEvent& event)
{
fm_assert(event.framebufferSize() == event.windowSize());
recalc_viewport(event.windowSize());
}
-void app::mousePressEvent(Platform::Sdl2Application::MouseEvent& event)
+void main_impl::mousePressEvent(Platform::Sdl2Application::MouseEvent& event)
{
if (_imgui.handleMousePressEvent(event))
return event.setAccepted();
@@ -25,14 +23,14 @@ void app::mousePressEvent(Platform::Sdl2Application::MouseEvent& event)
}
}
-void app::mouseReleaseEvent(Platform::Sdl2Application::MouseEvent& event)
+void main_impl::mouseReleaseEvent(Platform::Sdl2Application::MouseEvent& event)
{
if (_imgui.handleMouseReleaseEvent(event))
return event.setAccepted();
do_mouse_release((int)event.button());
}
-void app::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent& event)
+void main_impl::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent& event)
{
_cursor_in_imgui = _imgui.handleMouseMoveEvent(event);
if (_cursor_in_imgui)
@@ -44,13 +42,13 @@ void app::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent& event)
do_mouse_move(*_cursor_tile);
}
-void app::mouseScrollEvent(Platform::Sdl2Application::MouseScrollEvent& event)
+void main_impl::mouseScrollEvent(Platform::Sdl2Application::MouseScrollEvent& event)
{
if (_imgui.handleMouseScrollEvent(event))
return event.setAccepted();
}
-void app::textInputEvent(Platform::Sdl2Application::TextInputEvent& event)
+void main_impl::textInputEvent(Platform::Sdl2Application::TextInputEvent& event)
{
if (_imgui.handleTextInputEvent(event))
{
@@ -59,7 +57,7 @@ void app::textInputEvent(Platform::Sdl2Application::TextInputEvent& event)
}
}
-void app::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
+void main_impl::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
{
if (_imgui.handleKeyPressEvent(event))
{
@@ -69,7 +67,7 @@ void app::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
do_key(event.key(), event.modifiers(), true, event.isRepeated());
}
-void app::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
+void main_impl::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
{
if (_imgui.handleKeyReleaseEvent(event))
{
@@ -79,7 +77,7 @@ void app::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
do_key(event.key(), event.modifiers(), false, false);
}
-void app::anyEvent(SDL_Event& event)
+void main_impl::anyEvent(SDL_Event& event)
{
if (event.type == SDL_WINDOWEVENT)
switch (event.window.event)
@@ -97,25 +95,16 @@ void app::anyEvent(SDL_Event& event)
}
}
-void app::event_focus_out()
+void main_impl::event_focus_out() // TODO move to app
{
_cursor_pixel = std::nullopt;
recalc_cursor_tile();
}
-void app::event_focus_in()
-{
-}
-
-void app::event_mouse_leave()
+void main_impl::event_mouse_leave() // TODO move to app
{
_cursor_pixel = std::nullopt;
recalc_cursor_tile();
}
-void app::event_mouse_enter()
-{
-}
-
-
} // namespace floormat
diff --git a/main/floormat-app.cpp b/main/floormat-app.cpp
new file mode 100644
index 00000000..c16bbf4b
--- /dev/null
+++ b/main/floormat-app.cpp
@@ -0,0 +1,8 @@
+#include "floormat-app.hpp"
+
+namespace floormat {
+
+floormat_app::floormat_app() noexcept = default;
+floormat_app::~floormat_app() noexcept = default;
+
+} // namespace floormat
diff --git a/main/floormat-app.hpp b/main/floormat-app.hpp
new file mode 100644
index 00000000..f5e57c6e
--- /dev/null
+++ b/main/floormat-app.hpp
@@ -0,0 +1,44 @@
+#pragma once
+#include "compat/defs.hpp"
+
+namespace Magnum::Math { template<typename T> class Vector2; }
+
+namespace floormat {
+
+struct mouse_move_event;
+struct mouse_button_event;
+struct mouse_scroll_event;
+struct key_event;
+struct text_input_event;
+struct any_event;
+
+struct floormat_app
+{
+ floormat_app() noexcept;
+ virtual ~floormat_app() noexcept;
+
+ fm_DECLARE_DELETED_COPY_ASSIGNMENT(floormat_app);
+ fm_DECLARE_DEPRECATED_MOVE_ASSIGNMENT(floormat_app);
+
+ virtual void update(double dt) = 0;
+ virtual void draw_msaa();
+ virtual void draw() = 0;
+
+ virtual bool on_mouse_move(const mouse_move_event& event) noexcept = 0;
+ virtual bool on_mouse_down(const mouse_button_event& event) noexcept = 0;
+ virtual bool on_mouse_up(const mouse_button_event& event) noexcept = 0;
+ virtual bool on_mouse_scroll(const mouse_scroll_event& event) noexcept = 0;
+ virtual bool on_key_down(const key_event& event) noexcept = 0;
+ virtual bool on_key_up(const key_event& event) noexcept = 0;
+ virtual bool on_text_input_event(const text_input_event& event) noexcept = 0;
+ virtual void on_viewport_event(const Magnum::Math::Vector2<int>& size) noexcept = 0;
+ virtual bool on_any_event(const any_event& event) noexcept = 0;
+ virtual void on_focus_in() noexcept = 0;
+ virtual void on_focus_out() noexcept = 0;
+ virtual void on_mouse_leave() noexcept = 0;
+ virtual void on_mouse_enter() noexcept = 0;
+};
+
+inline void floormat_app::draw_msaa() {}
+
+} // namespace floormat
diff --git a/main/floormat-events.cpp b/main/floormat-events.cpp
new file mode 100644
index 00000000..55fb7a91
--- /dev/null
+++ b/main/floormat-events.cpp
@@ -0,0 +1,100 @@
+#pragma once
+#include "floormat-main.hpp"
+#include "compat/assert.hpp"
+#include <SDL_events.h>
+#include <SDL_video.h>
+
+namespace floormat {
+
+void main_impl::viewportEvent(Platform::Sdl2Application::ViewportEvent& event)
+{
+ fm_assert(event.framebufferSize() == event.windowSize());
+ recalc_viewport(event.windowSize());
+ app.viewport_event(event.windowSize());
+}
+
+void main_impl::mousePressEvent(Platform::Sdl2Application::MouseEvent& event)
+{
+ if (app.)
+ if (_imgui.handleMousePressEvent(event))
+ return event.setAccepted();
+ else if (_cursor_tile)
+ {
+ const auto& tile = *_cursor_tile;
+ do_mouse_click(tile, (int)event.button());
+ }
+}
+
+void main_impl::mouseReleaseEvent(Platform::Sdl2Application::MouseEvent& event)
+{
+ if (_imgui.handleMouseReleaseEvent(event))
+ return event.setAccepted();
+ do_mouse_release((int)event.button());
+}
+
+void main_impl::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent& event)
+{
+ _cursor_in_imgui = _imgui.handleMouseMoveEvent(event);
+ if (_cursor_in_imgui)
+ _cursor_pixel = std::nullopt;
+ else
+ _cursor_pixel = event.position();
+ recalc_cursor_tile();
+ if (_cursor_tile)
+ do_mouse_move(*_cursor_tile);
+}
+
+void main_impl::mouseScrollEvent(Platform::Sdl2Application::MouseScrollEvent& event)
+{
+ if (_imgui.handleMouseScrollEvent(event))
+ return event.setAccepted();
+}
+
+void main_impl::textInputEvent(Platform::Sdl2Application::TextInputEvent& event)
+{
+ if (_imgui.handleTextInputEvent(event))
+ {
+ keys = {};
+ event.setAccepted();
+ }
+}
+
+void main_impl::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
+{
+ if (_imgui.handleKeyPressEvent(event))
+ {
+ keys = {};
+ return event.setAccepted();
+ }
+ do_key(event.key(), event.modifiers(), true, event.isRepeated());
+}
+
+void main_impl::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
+{
+ if (_imgui.handleKeyReleaseEvent(event))
+ {
+ keys = {};
+ return event.setAccepted();
+ }
+ do_key(event.key(), event.modifiers(), false, false);
+}
+
+void main_impl::anyEvent(SDL_Event& event)
+{
+ if (event.type == SDL_WINDOWEVENT)
+ switch (event.window.event)
+ {
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ return app.event_focus_out();
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ return app.event_focus_in();
+ case SDL_WINDOWEVENT_LEAVE:
+ return app.event_mouse_leave();
+ case SDL_WINDOWEVENT_ENTER:
+ return app.event_mouse_enter();
+ default:
+ std::fputs("", stdout); break; // put breakpoint here
+ }
+}
+} // namespace floormat
+
diff --git a/main/floormat-main-impl.cpp b/main/floormat-main-impl.cpp
new file mode 100644
index 00000000..56c19882
--- /dev/null
+++ b/main/floormat-main-impl.cpp
@@ -0,0 +1,106 @@
+#include "floormat-main-impl.hpp"
+#include "floormat.hpp"
+#include "floormat-app.hpp"
+#include "compat/assert.hpp"
+#include "compat/fpu.hpp"
+
+namespace floormat {
+
+floormat_main::floormat_main() noexcept = default;
+floormat_main::~floormat_main() noexcept = default;
+
+static const char* const fm_fake_argv[] = { "floormat", nullptr };
+
+auto main_impl::make_window_flags(const fm_options& s) -> Configuration::WindowFlags
+{
+ using flag = Configuration::WindowFlag;
+ Configuration::WindowFlags flags{};
+ if (s.resizable)
+ flags |= flag::Resizable;
+ if (s.fullscreen)
+ flags |= flag::Fullscreen;
+ if (s.fullscreen_desktop)
+ flags |= flag::FullscreenDesktop;
+ if (s.borderless)
+ flags |= flag::Borderless;
+ if (s.maximized)
+ flags |= flag::Maximized;
+ return flags;
+}
+
+void main_impl::recalc_viewport(Vector2i size)
+{
+ GL::defaultFramebuffer.setViewport({{}, size });
+#ifdef FM_MSAA
+ _msaa_framebuffer.detach(GL::Framebuffer::ColorAttachment{0});
+ _msaa_renderbuffer = Magnum::GL::Renderbuffer{};
+ _msaa_renderbuffer.setStorageMultisample(s.msaa_samples, GL::RenderbufferFormat::RGBA8, size);
+ _msaa_framebuffer.setViewport({{}, size });
+ _msaa_framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _msaa_renderbuffer);
+#endif
+ _shader.set_scale(Vector2(size));
+ app.on_viewport_event(size);
+ setMinimalLoopPeriod(5);
+}
+
+auto main_impl::make_conf(const fm_options& s) -> Configuration
+{
+ return Configuration{}
+ .setTitle(s.title)
+ .setSize(s.resolution)
+ .setWindowFlags(make_window_flags(s));
+}
+
+main_impl::main_impl(floormat_app& app, const fm_options& s) :
+ Platform::Sdl2Application{Arguments{fake_argc, fm_fake_argv},
+ make_conf(s), make_gl_conf(s)},
+ app{app}, s{s}
+{
+ switch (s.vsync)
+ {
+ case fm_tristate::on:
+ (void)setSwapInterval(1);
+ if (const auto list = GL::Context::current().extensionStrings();
+ std::find(list.cbegin(), list.cend(), "EXT_swap_control_tear") != list.cbegin())
+ (void)setSwapInterval(-1);
+ break;
+ case fm_tristate::off:
+ setSwapInterval(0);
+ break;
+ default: break;
+ }
+ set_fp_mask();
+ fm_assert(framebufferSize() == windowSize());
+ recalc_viewport(windowSize());
+ timeline.start();
+}
+
+main_impl::~main_impl() = default;
+
+void main_impl::drawEvent()
+{
+ if (const float dt = timeline.previousFrameDuration(); dt > 0)
+ {
+ constexpr float RC = 0.1f;
+ const float alpha = dt/(dt + RC);
+
+ _frame_time = _frame_time*(1-alpha) + alpha*dt;
+ }
+ else
+ swapBuffers();
+ timeline.nextFrame();
+
+ const auto dt = std::clamp((double)timeline.previousFrameDuration(), 1e-6, 1e-1);
+ app.update(dt);
+
+ _shader.set_tint({1, 1, 1, 1});
+}
+
+floormat_main* floormat_main::create(floormat_app& app, const fm_options& options)
+{
+ auto* ret = new main_impl(app, options);
+ fm_assert(ret);
+ return ret;
+}
+
+} // namespace floormat
diff --git a/main/floormat-main-impl.hpp b/main/floormat-main-impl.hpp
new file mode 100644
index 00000000..e0cb0747
--- /dev/null
+++ b/main/floormat-main-impl.hpp
@@ -0,0 +1,66 @@
+#pragma once
+#include "floormat.hpp"
+#include "floormat-main.hpp"
+#include "shaders/tile-shader.hpp"
+#include <Corrade/Containers/String.h>
+#include <Magnum/GL/RenderbufferFormat.h>
+#include <Magnum/Platform/Sdl2Application.h>
+
+#define FM_MSAA
+
+namespace floormat {
+
+struct floormat_app;
+
+struct main_impl final : Platform::Sdl2Application, floormat_main
+{
+ main_impl(floormat_app& app, const fm_options& opts);
+ ~main_impl() override;
+
+ void quit(int status) override;
+
+ Magnum::Math::Vector2<int> window_size() const noexcept override;
+ tile_shader& shader() noexcept override;
+ void register_debug_callback() noexcept override;
+
+ struct world& world() noexcept override;
+ SDL_Window* window() noexcept override;
+ float smoothed_dt() const noexcept override;
+
+ [[maybe_unused]] void viewportEvent(ViewportEvent& event) override;
+ [[maybe_unused]] void mousePressEvent(MouseEvent& event) override;
+ [[maybe_unused]] void mouseReleaseEvent(MouseEvent& event) override;
+ [[maybe_unused]] void mouseMoveEvent(MouseMoveEvent& event) override;
+ [[maybe_unused]] void mouseScrollEvent(MouseScrollEvent& event) override;
+ [[maybe_unused]] void textInputEvent(TextInputEvent& event) override;
+ [[maybe_unused]] void keyPressEvent(KeyEvent& event) override;
+ [[maybe_unused]] void keyReleaseEvent(KeyEvent& event) override;
+ [[maybe_unused]] void anyEvent(SDL_Event& event) override;
+ void drawEvent() override;
+
+private:
+ float _frame_time = 0;
+ floormat_app& app;
+ fm_options s;
+ tile_shader _shader;
+ Magnum::Timeline timeline;
+ int fake_argc = 1;
+
+#ifdef FM_MSAA
+ GL::Framebuffer _msaa_framebuffer{{{}, windowSize()}};
+ GL::Renderbuffer _msaa_renderbuffer{};
+#endif
+
+ void recalc_viewport(Vector2i size);
+
+ void debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
+ GL::DebugOutput::Severity severity, const std::string& str) const;
+ static void _debug_callback(GL::DebugOutput::Source src, GL::DebugOutput::Type type, UnsignedInt id,
+ GL::DebugOutput::Severity severity, const std::string& str, const void* self);
+
+ static Configuration make_conf(const fm_options& s);
+ static GLConfiguration make_gl_conf(const fm_options& s);
+ static Configuration::WindowFlags make_window_flags(const fm_options& s);
+};
+
+} // namespace floormat
diff --git a/main/floormat-main.hpp b/main/floormat-main.hpp
new file mode 100644
index 00000000..5f0635cc
--- /dev/null
+++ b/main/floormat-main.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "floormat.hpp"
+#include <Magnum/Math/Vector2.h>
+
+struct SDL_Window;
+
+namespace floormat {
+
+struct floormat_app;
+struct tile_shader;
+struct world;
+
+struct floormat_main
+{
+ floormat_main() noexcept;
+ virtual ~floormat_main() noexcept;
+
+ fm_DECLARE_DELETED_COPY_ASSIGNMENT(floormat_main);
+ fm_DECLARE_DEPRECATED_MOVE_ASSIGNMENT(floormat_main);
+
+ virtual void quit(int status) = 0;
+
+ virtual Magnum::Math::Vector2<int> window_size() const noexcept = 0;
+ virtual float smoothed_dt() const noexcept = 0;
+ virtual tile_shader& shader() noexcept = 0;
+ virtual void register_debug_callback() noexcept = 0;
+
+ virtual world& world() noexcept = 0;
+ virtual SDL_Window* window() noexcept = 0;
+
+ static floormat_main* create(floormat_app& app, const fm_options& options);
+};
+
+} // namespace floormat
diff --git a/main/floormat.hpp b/main/floormat.hpp
new file mode 100644
index 00000000..49b7ec76
--- /dev/null
+++ b/main/floormat.hpp
@@ -0,0 +1,30 @@
+#pragma once
+#include <cstdint>
+#include <Corrade/Containers/String.h>
+#include <Magnum/Math/Vector2.h>
+
+namespace floormat {
+
+enum class fm_gpu_debug : char { no_error = -1, on, off };
+enum class fm_tristate : char { maybe = -1, on, off };
+enum class fm_log_level : unsigned char { quiet, normal, verbose, };
+
+struct fm_options final
+{
+ Magnum::Math::Vector2<int> resolution{1024, 768};
+ Containers::String title{"Test"};
+ Containers::String disabled_extensions; // TODO
+ std::uint8_t msaa_samples = 4;
+ fm_tristate vsync = fm_tristate::maybe;
+ fm_gpu_debug gpu_debug = fm_gpu_debug::on; // TODO
+ fm_log_level log_level = fm_log_level::normal; // TODO
+ std::uint8_t resizable : 1 = true,
+ fullscreen : 1 = false,
+ fullscreen_desktop : 1 = false,
+ borderless : 1 = false,
+ maximized : 1 = false,
+ msaa : 1 = true; // TODO
+};
+
+} // namespace floormat
+
diff --git a/main/imgui-raii.hpp b/main/imgui-raii.hpp
deleted file mode 100644
index afae29d6..00000000
--- a/main/imgui-raii.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#pragma once
-
-#include <Corrade/Containers/StringView.h>
-#include <Magnum/Math/Color.h>
-#ifndef __CLION_IDE__zz
-#include <imgui.h>
-#endif
-
-namespace floormat::imgui {
-
-struct raii_wrapper final
-{
- using F = void(*)(void);
- raii_wrapper(F fn) : dtor{fn} {}
- raii_wrapper() = default;
- ~raii_wrapper() { if (dtor) dtor(); }
- raii_wrapper(const raii_wrapper&) = delete;
- raii_wrapper& operator=(const raii_wrapper&) = delete;
- raii_wrapper& operator=(raii_wrapper&&) = delete;
- raii_wrapper(raii_wrapper&& other) noexcept : dtor{other.dtor} { other.dtor = nullptr; }
- inline operator bool() const noexcept { return dtor != nullptr; }
-
- F dtor = nullptr;
-};
-
-[[nodiscard]] static inline raii_wrapper begin_window(Containers::StringView name = {},
- ImGuiWindowFlags_ flags = ImGuiWindowFlags_None)
-{
- if (name.isEmpty())
- name = "floormat editor";
- if (ImGui::Begin(name.data(), nullptr, flags))
- return {&ImGui::End};
- else
- return {};
-}
-
-[[nodiscard]] static inline raii_wrapper begin_main_menu()
-{
- if (ImGui::BeginMainMenuBar())
- return {&ImGui::EndMainMenuBar};
- else
- return {};
-}
-[[nodiscard]] static inline raii_wrapper begin_menu(Containers::StringView name, bool enabled = true)
-{
- if (ImGui::BeginMenu(name.data(), enabled))
- return {&ImGui::EndMenu};
- else
- return {};
-}
-
-[[nodiscard]] static inline raii_wrapper begin_list_box(Containers::StringView name, ImVec2 size = {})
-{
- if (ImGui::BeginListBox(name.data(), size))
- return {&ImGui::EndListBox};
- else
- return {};
-}
-
-[[nodiscard]] static inline raii_wrapper tree_node(Containers::StringView name, ImGuiTreeNodeFlags_ flags = ImGuiTreeNodeFlags_None)
-{
- if (ImGui::TreeNodeEx(name.data(), flags))
- return {&ImGui::TreePop};
- else
- return {};
-}
-
-[[nodiscard]] static inline raii_wrapper push_style_var(ImGuiStyleVar_ var, Vector2 value)
-{
- ImGui::PushStyleVar(var, {value[0], value[1]});
- return {[]{ ImGui::PopStyleVar(); }};
-}
-
-[[nodiscard]] static inline raii_wrapper push_style_var(ImGuiStyleVar_ var, float value)
-{
- ImGui::PushStyleVar(var, value);
- return {[]{ ImGui::PopStyleVar(); }};
-}
-
-[[nodiscard]] static inline raii_wrapper push_style_color(ImGuiCol_ var, const Color4& value)
-{
- ImGui::PushStyleColor(var, {value[0], value[1], value[2], value[3]});
- return {[]{ ImGui::PopStyleColor(); }};
-}
-
-} // namespace floormat::imgui
diff --git a/main/imgui.cpp b/main/imgui.cpp
deleted file mode 100644
index b0777d5d..00000000
--- a/main/imgui.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-#include "app.hpp"
-#include <Magnum/GL/Renderer.h>
-#include "imgui-raii.hpp"
-#include <Magnum/ImGuiIntegration/Context.h>
-
-namespace floormat {
-
-using namespace floormat::imgui;
-
-void app::init_imgui(Vector2i size)
-{
- if (!_imgui.context())
- _imgui = ImGuiIntegration::Context(Vector2{size}, size, size);
- else
- _imgui.relayout(Vector2{size}, size, size);
-}
-
-void app::render_menu()
-{
- GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add, GL::Renderer::BlendEquation::Add);
- GL::Renderer::setBlendFunction(GL::Renderer::BlendFunction::SourceAlpha, GL::Renderer::BlendFunction::OneMinusSourceAlpha);
- GL::Renderer::enable(GL::Renderer::Feature::Blending);
-
- GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
- GL::Renderer::disable(GL::Renderer::Feature::FaceCulling);
- GL::Renderer::disable(GL::Renderer::Feature::DepthTest);
-
- _imgui.drawFrame();
-}
-
-float app::draw_main_menu()
-{
- float main_menu_height = 0;
- if (auto b = begin_main_menu())
- {
- if (auto b = begin_menu("File"))
- {
- ImGui::MenuItem("Open", "Ctrl+O");
- ImGui::MenuItem("Recent");
- ImGui::Separator();
- ImGui::MenuItem("Save", "Ctrl+S");
- ImGui::MenuItem("Save as...", "Ctrl+Shift+S");
- ImGui::Separator();
- ImGui::MenuItem("Close");
- }
- if (auto b = begin_menu("Mode"))
- {
- ImGui::MenuItem("Select", "F1", _editor.mode() == editor_mode::select);
- ImGui::MenuItem("Floor", "F2", _editor.mode() == editor_mode::floor);
- ImGui::MenuItem("Walls", "F3", _editor.mode() == editor_mode::walls);
- }
-
- main_menu_height = ImGui::GetContentRegionMax().y;
- }
- return main_menu_height;
-}
-
-void app::draw_ui()
-{
- ImGui::GetIO().IniFilename = nullptr;
- _imgui.newFrame();
- ImGui::StyleColorsDark(&ImGui::GetStyle());
-
- const float main_menu_height = draw_main_menu();
- draw_editor_pane(_editor.floor(), main_menu_height);
- draw_fps();
- draw_cursor_coord();
- ImGui::EndFrame();
-}
-
-void app::draw_editor_pane(tile_type& type, float main_menu_height)
-{
- constexpr
- Color4 color_perm_selected{1, 1, 1, .7f},
- color_selected{1, 0.843f, 0, .8f},
- color_hover{0, .8f, 1, .7f};
-
- if (ImGui::GetIO().WantTextInput && !isTextInputActive())
- startTextInput();
- else if (!ImGui::GetIO().WantTextInput && isTextInputActive())
- stopTextInput();
-
- [[maybe_unused]] const raii_wrapper vars[] = {
- push_style_var(ImGuiStyleVar_WindowPadding, {8, 8}),
- push_style_var(ImGuiStyleVar_WindowBorderSize, 0),
- push_style_var(ImGuiStyleVar_FramePadding, {4, 4}),
- push_style_color(ImGuiCol_WindowBg, {0, 0, 0, .5}),
- push_style_color(ImGuiCol_FrameBg, {0, 0, 0, 0}),
- };
-
- const auto& style = ImGui::GetStyle();
- tile_type* const ed = _editor.current();
-
- if (main_menu_height > 0)
- {
- ImGui::SetNextWindowPos({0, main_menu_height+style.WindowPadding.y});
- ImGui::SetNextFrameWantCaptureKeyboard(false);
- ImGui::SetNextWindowSize({420, windowSize()[1] - main_menu_height - style.WindowPadding.y});
- if (const auto flags = ImGuiWindowFlags_(ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings);
- auto b = begin_window({}, flags))
- {
- const float window_width = ImGui::GetWindowWidth() - 32;
-
- char buf[128];
- //ImGui::SetNextWindowBgAlpha(.2f);
-
- if (auto b = begin_list_box("##atlases", {-FLT_MIN, -1}))
- {
- for (const auto& [k, v] : type)
- {
- ///const auto& k_ = k;
- const auto& v_ = v;
- const auto click_event = [&] {
- if (ed)
- {
- if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
- ed->select_tile_permutation(v_);
- else if (ImGui::IsItemClicked(ImGuiMouseButton_Middle))
- ed->clear_selection();
- }
- };
- const auto do_caption = [&] {
- if (ed)
- {
- click_event();
- if (ed->is_atlas_selected(v))
- {
- ImGui::SameLine();
- ImGui::Text(" (selected)");
- }
- }
- {
- snprintf(buf, sizeof(buf), "%zu", (std::size_t)v_->num_tiles());
- ImGui::SameLine(window_width - ImGui::CalcTextSize(buf).x - style.FramePadding.x - 4);
- ImGui::Text("%s", buf);
- }
- };
- const auto N = v->num_tiles();
- if (const auto flags = ImGuiTreeNodeFlags_(ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Framed);
- auto b = tree_node(k.data(), flags))
- {
- do_caption();
- [[maybe_unused]] const raii_wrapper vars[] = {
- push_style_var(ImGuiStyleVar_FramePadding, {2, 2}),
- push_style_color(ImGuiCol_ButtonHovered, color_hover),
- };
- const bool perm_selected = ed ? ed->is_permutation_selected(v) : false;
- constexpr std::size_t per_row = 8;
- for (std::size_t i = 0; i < N; i++)
- {
- const bool selected = ed ? ed->is_tile_selected(v, i) : false;
-
- if (i > 0 && i % per_row == 0)
- ImGui::NewLine();
-
- [[maybe_unused]] const raii_wrapper vars[] = {
- selected ? push_style_color(ImGuiCol_Button, color_selected) : raii_wrapper{},
- selected ? push_style_color(ImGuiCol_ButtonHovered, color_selected) : raii_wrapper{},
- perm_selected ? push_style_color(ImGuiCol_Button, color_perm_selected) : raii_wrapper{},
- perm_selected ? push_style_color(ImGuiCol_ButtonHovered, color_perm_selected) : raii_wrapper{},
- };
-
- snprintf(buf, sizeof(buf), "##item_%zu", i);
- const auto uv = v->texcoords_for_id(i);
- ImGui::ImageButton(buf, (void*)&v->texture(), {TILE_SIZE[0]/2, TILE_SIZE[1]/2},
- { uv[3][0], uv[3][1] }, { uv[0][0], uv[0][1] });
- if (ed)
- {
- if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
- ed->select_tile(v, i);
- else
- click_event();
- }
- ImGui::SameLine();
- }
- ImGui::NewLine();
- }
- else
- do_caption();
- }
- }
- }
- }
-}
-
-void app::draw_fps()
-{
- auto c1 = push_style_var(ImGuiStyleVar_FramePadding, {0, 0});
- auto c2 = push_style_var(ImGuiStyleVar_WindowPadding, {0, 0});
- auto c3 = push_style_var(ImGuiStyleVar_WindowBorderSize, 0);
- auto c4 = push_style_var(ImGuiStyleVar_WindowMinSize, {1, 1});
- auto c5 = push_style_var(ImGuiStyleVar_ScrollbarSize, 0);
- auto c6 = push_style_color(ImGuiCol_Text, {0, 1, 0, 1});
-
- char buf[16];
- const double hz = _frame_time > 1e-6f ? (int)std::round(10./(double)_frame_time + .05) * .1 : 9999;
- snprintf(buf, sizeof(buf), "%.1f FPS", hz);
- const ImVec2 size = ImGui::CalcTextSize(buf);
-
- ImGui::SetNextWindowPos({windowSize()[0] - size.x - 4, 3});
- ImGui::SetNextWindowSize(size);
-
- if (auto flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs |
- ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground;
- auto b = begin_window("framerate", ImGuiWindowFlags_(flags)))
- {
- ImGui::Text("%s", buf);
- }
-}
-
-void app::draw_cursor_coord()
-{
- if (!_cursor_tile)
- return;
-
- auto c1 = push_style_var(ImGuiStyleVar_FramePadding, {0, 0});
- auto c2 = push_style_var(ImGuiStyleVar_WindowPadding, {0, 0});
- auto c3 = push_style_var(ImGuiStyleVar_WindowBorderSize, 0);
- auto c4 = push_style_var(ImGuiStyleVar_WindowMinSize, {1, 1});
- auto c5 = push_style_var(ImGuiStyleVar_ScrollbarSize, 0);
- auto c6 = push_style_color(ImGuiCol_Text, {.9f, .9f, .9f, 1});
-
- char buf[64];
- const auto coord = *_cursor_tile;
- const auto chunk = coord.chunk();
- const auto local = coord.local();
- snprintf(buf, sizeof(buf), "%hd:%hd - %hhu:%hhu", chunk.x, chunk.y, local.x, local.y);
- const auto size = ImGui::CalcTextSize(buf);
-
- ImGui::SetNextWindowPos({windowSize()[0]/2 - size.x/2, 3});
- ImGui::SetNextWindowSize(size);
- if (auto flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs |
- ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground;
- auto b = begin_window("tile-coord", ImGuiWindowFlags_(flags)))
- {
- ImGui::Text("%s", buf);
- }
-}
-
-} // namespace floormat
diff --git a/main/keyboard.cpp b/main/keyboard.cpp
deleted file mode 100644
index a700d0f4..00000000
--- a/main/keyboard.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "app.hpp"
-
-namespace floormat {
-
-void app::do_key(KeyEvent::Key k, KeyEvent::Modifiers m, bool pressed, bool repeated)
-{
- //using Mods = KeyEvent::Modifiers;
-
- (void)m;
- (void)repeated;
-
- const key x = fm_begin(switch (k)
- {
- using enum KeyEvent::Key;
- using enum key;
-
- default: return COUNT;
- case W: return camera_up;
- case A: return camera_left;
- case S: return camera_down;
- case D: return camera_right;
- case Home: return camera_reset;
- case R: return rotate_tile;
- case F5: return quicksave;
- case F9: return quickload;
- case Esc: return quit;
- });
-
- if (x != key::COUNT)
- keys[x] = pressed;
-}
-
-app::~app()
-{
- loader_::destroy();
-}
-
-} // namespace floormat
diff --git a/main/loader-impl.cpp b/main/loader-impl.cpp
deleted file mode 100644
index 5cbe1759..00000000
--- a/main/loader-impl.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "loader.hpp"
-#include "tile-atlas.hpp"
-#include "compat/assert.hpp"
-#include "compat/alloca.hpp"
-#include <filesystem>
-#include <unordered_map>
-#include <utility>
-#include <optional>
-#include <Corrade/Containers/Optional.h>
-#include <Corrade/Containers/Pair.h>
-#include <Corrade/Containers/StringStlView.h>
-#include <Corrade/PluginManager/PluginManager.h>
-#include <Corrade/Utility/Resource.h>
-#include <Corrade/Utility/Path.h>
-#include <Magnum/ImageView.h>
-#include <Magnum/Trade/AbstractImporter.h>
-#include <Magnum/Trade/ImageData.h>
-#include <Magnum/Trade/AbstractImageConverter.h>
-
-#ifdef __GNUG__
-#pragma GCC diagnostic ignored "-Walloca"
-#endif
-
-namespace floormat {
-
-struct loader_impl final : loader_
-{
- std::optional<Utility::Resource> shader_res;
- PluginManager::Manager<Trade::AbstractImporter> importer_plugins;
- Containers::Pointer<Trade::AbstractImporter> tga_importer =
- importer_plugins.loadAndInstantiate("AnyImageImporter");
-
- PluginManager::Manager<Trade::AbstractImageConverter> image_converter_plugins;
- Containers::Pointer<Trade::AbstractImageConverter> tga_converter =
- image_converter_plugins.loadAndInstantiate("AnyImageConverter");
-
- std::unordered_map<std::string, std::shared_ptr<struct tile_atlas>> atlas_map;
-
- std::string shader(Containers::StringView filename) override;
- Trade::ImageData2D tile_texture(Containers::StringView filename) override;
- std::shared_ptr<struct tile_atlas> tile_atlas(Containers::StringView filename, Vector2ub size) override;
-
- static void set_application_working_directory();
-
- explicit loader_impl();
- ~loader_impl() override;
-};
-
-std::string loader_impl::shader(Containers::StringView filename)
-{
- if (!shader_res)
- shader_res = std::make_optional<Utility::Resource>("floormat/shaders");
- auto ret = shader_res->getString(filename);
- if (ret.isEmpty())
- fm_abort("can't find shader resource '%s'", filename.cbegin());
- return ret;
-}
-
-std::shared_ptr<tile_atlas> loader_impl::tile_atlas(Containers::StringView name, Vector2ub size)
-{
- auto it = std::find_if(atlas_map.begin(), atlas_map.end(), [&](const auto& x) {
- const auto& [k, v] = x;
- return Containers::StringView{k} == name;
- });
- if (it != atlas_map.end())
- return it->second;
- auto image = tile_texture(name);
- auto atlas = std::make_shared<struct tile_atlas>(name, image, size);
- atlas_map[name] = atlas;
- return atlas;
-}
-
-Trade::ImageData2D loader_impl::tile_texture(Containers::StringView filename_)
-{
- static_assert(IMAGE_PATH[sizeof(IMAGE_PATH)-2] == '/');
- fm_assert(filename_.size() < 4096);
- fm_assert(filename_.find('\\') == filename_.end());
- fm_assert(tga_importer);
- constexpr std::size_t max_extension_length = 16;
-
- char* const filename = (char*)alloca(filename_.size() + std::size(IMAGE_PATH) + max_extension_length);
- const std::size_t len = fm_begin(
- std::size_t off = std::size(IMAGE_PATH)-1;
- std::memcpy(filename, IMAGE_PATH, off);
- std::memcpy(filename + off, filename_.cbegin(), filename_.size());
- return off + filename_.size();
- );
-
- for (const auto& extension : std::initializer_list<Containers::StringView>{ ".tga", ".png", ".webp", })
- {
- std::memcpy(filename + len, extension.data(), extension.size());
- filename[len + extension.size()] = '\0';
- if (tga_importer->openFile(filename))
- {
- auto img = tga_importer->image2D(0);
- if (!img)
- fm_abort("can't allocate tile image for '%s'", filename);
- auto ret = std::move(*img);
- return ret;
- }
- Debug{} << "failed to open" << filename << extension;
- }
- const auto path = Utility::Path::currentDirectory();
- fm_log("fatal: can't open tile image '%s' (cwd '%s')", filename, path ? path->data() : "(null)");
- std::abort();
-}
-
-void loader_::destroy()
-{
- loader.~loader_();
- new (&loader) loader_impl();
-}
-
-void loader_impl::set_application_working_directory()
-{
- static bool once = false;
- if (once)
- return;
- once = true;
- const auto location = Utility::Path::executableLocation();
- if (!location)
- return;
- std::filesystem::path path((std::string)*location);
- path.replace_filename("..");
- std::error_code error;
- std::filesystem::current_path(path, error);
- if (error.value()) {
- fm_warn("failed to change working directory to '%s' (%s)",
- path.string().data(), error.message().data());
- }
-}
-
-loader_impl::loader_impl()
-{
- set_application_working_directory();
-}
-
-loader_impl::~loader_impl() = default;
-
-static loader_& make_default_loader()
-{
- static loader_impl loader_singleton{};
- return loader_singleton;
-}
-
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-loader_& loader = make_default_loader();
-
-} // namespace floormat
diff --git a/main/app.cpp b/main/main.cpp
index d6593227..37e7164b 100644
--- a/main/app.cpp
+++ b/main/main.cpp
@@ -1,6 +1,6 @@
#include <cstddef>
#include "compat/sysexits.hpp"
-#include "app.hpp"
+#include "main.hpp"
#include "compat/fpu.hpp"
#include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/DebugStl.h>
@@ -12,7 +12,7 @@
namespace floormat {
-int app::run_from_argv(int argc, char** argv)
+int floormat::run_from_argv(int argc, char** argv)
{
Corrade::Utility::Arguments args{};
app_settings opts;
@@ -20,17 +20,17 @@ int app::run_from_argv(int argc, char** argv)
.addOption("vsync", opts.vsync ? "1" : "0")
.parse(argc, argv);
opts.vsync = args.value<bool>("vsync");
- app x{{argc, argv}, std::move(opts)}; // NOLINT(performance-move-const-arg)
+ floormat x{{argc, argv}, std::move(opts)}; // NOLINT(performance-move-const-arg)
return x.exec();
}
-void app::usage(const Utility::Arguments& args)
+void floormat::usage(const Utility::Arguments& args)
{
Error{Error::Flag::NoNewlineAtTheEnd} << args.usage();
std::exit(EX_USAGE); // NOLINT(concurrency-mt-unsafe)
}
-app::app(const Arguments& arguments, app_settings opts):
+floormat::floormat(const Arguments& arguments, app_settings opts):
Platform::Sdl2Application{
arguments,
Configuration{}
@@ -67,7 +67,7 @@ app::app(const Arguments& arguments, app_settings opts):
timeline.start();
}
-void app::recalc_viewport(Vector2i size)
+void floormat::recalc_viewport(Vector2i size)
{
_shader.set_scale(Vector2(size));
init_imgui(size);
@@ -88,7 +88,7 @@ void app::recalc_viewport(Vector2i size)
int main(int argc, char** argv)
{
- return floormat::app::run_from_argv(argc, argv);
+ return floormat::floormat::run_from_argv(argc, argv);
}
#ifdef _MSC_VER
diff --git a/main/app.hpp b/main/main.hpp
index 8970aa15..98552a7c 100644
--- a/main/app.hpp
+++ b/main/main.hpp
@@ -1,6 +1,9 @@
#pragma once
+
+#include "floormat.hpp"
+
#include "tile-atlas.hpp"
-#include "chunk.hpp"
+#include "src/chunk.hpp"
#include "shaders/tile-shader.hpp"
#include "src/loader.hpp"
#include "draw/floor-mesh.hpp"
@@ -9,8 +12,7 @@
#include "draw/wireframe-quad.hpp"
#include "draw/wireframe-box.hpp"
#include "compat/enum-bitset.hpp"
-#include "editor.hpp"
-#include "world.hpp"
+#include "src/world.hpp"
#include <Magnum/Timeline.h>
#include <Magnum/GL/DebugOutput.h>
#include <Magnum/Platform/Sdl2Application.h>
@@ -26,16 +28,16 @@
namespace floormat {
-struct app final : private Platform::Sdl2Application
+struct floormat final : private Platform::Sdl2Application
{
static int run_from_argv(int argc, char** argv);
- virtual ~app();
+ virtual ~floormat();
private:
struct app_settings;
[[maybe_unused]] [[noreturn]] static void usage(const Utility::Arguments& args);
- explicit app(const Arguments& arguments, app_settings opts);
+ explicit floormat(const Arguments& arguments, app_settings opts);
using dpi_policy = Platform::Implementation::Sdl2DpiScalingPolicy;
using tile_atlas_ = std::shared_ptr<tile_atlas>;
diff --git a/main/update.cpp b/main/update.cpp
deleted file mode 100644
index ebd1881b..00000000
--- a/main/update.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "app.hpp"
-
-namespace floormat {
-
-//#define FM_NO_BINDINGS
-
-void app::make_test_chunk(chunk& c)
-{
- constexpr auto N = TILE_MAX_DIM;
- for (auto [x, k, pt] : c) {
-#if defined FM_NO_BINDINGS
- const auto& atlas = floor1;
-#else
- const auto& atlas = pt.x != pt.y && (pt.x == N/2 || pt.y == N/2) ? floor2 : floor1;
-#endif
- x.ground_image = { atlas, k % atlas->num_tiles() };
- }
-#ifdef FM_NO_BINDINGS
- const auto& wall1 = floor1, wall2 = floor1;
-#endif
- constexpr auto K = N/2;
- c[{K, K }].wall_north = { wall1, 0 };
- c[{K, K }].wall_west = { wall2, 0 };
- c[{K, K+1}].wall_north = { wall1, 0 };
- c[{K+1, K }].wall_west = { wall2, 0 };
-}
-
-void app::do_mouse_click(const global_coords pos, int button)
-{
- if (button == SDL_BUTTON_LEFT)
- _editor.on_click(_world, pos);
- else
- _editor.on_release();
-}
-
-void app::do_mouse_release(int button)
-{
- (void)button;
- _editor.on_release();
-}
-
-void app::do_mouse_move(global_coords pos)
-{
- _editor.on_mouse_move(_world, pos);
-}
-
-void app::update(double dt)
-{
- do_camera(dt);
- draw_ui();
- if (keys[key::quit])
- Platform::Sdl2Application::exit(0);
-}
-
-} // namespace floormat