diff options
-rw-r--r-- | doc/userconfig-you@Clang.cmake | 13 | ||||
-rw-r--r-- | editor/editor.hpp | 25 | ||||
-rw-r--r-- | editor/precomp.hpp | 5 | ||||
-rw-r--r-- | editor/scenery-editor.cpp | 40 | ||||
-rw-r--r-- | editor/scenery-editor.hpp | 37 | ||||
-rw-r--r-- | loader/loader-impl.cpp | 78 | ||||
-rw-r--r-- | main/precomp.hpp | 2 | ||||
-rw-r--r-- | src/anim-atlas.cpp | 14 | ||||
-rw-r--r-- | src/anim-atlas.hpp | 3 | ||||
-rw-r--r-- | src/loader.hpp | 13 | ||||
-rw-r--r-- | src/scenery.hpp | 11 |
11 files changed, 181 insertions, 60 deletions
diff --git a/doc/userconfig-you@Clang.cmake b/doc/userconfig-you@Clang.cmake index 2f9a9987..543b36c7 100644 --- a/doc/userconfig-you@Clang.cmake +++ b/doc/userconfig-you@Clang.cmake @@ -1,16 +1,3 @@ -if(FLOORMAT_WITH-COVERAGE) - set(CMAKE_BUILD_TYPE DEBUG CACHE STRING "" FORCE) - add_definitions( - -fprofile-instr-generate - -fcoverage-mapping - -mllvm -runtime-counter-relocation=true - ) - add_link_options( - -fprofile-instr-generate - -fcoverage-mapping - ) -endif() - add_compile_options(-emit-llvm) sets(STRING CMAKE_C_FLAGS "" diff --git a/editor/editor.hpp b/editor/editor.hpp index 94cb7709..b25e6900 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -6,6 +6,7 @@ #include "scenery.hpp" #include "editor-enums.hpp" #include "tile-editor.hpp" +#include "scenery-editor.hpp" #include <optional> #include <map> @@ -18,30 +19,6 @@ struct world; struct anim_atlas; struct tile_atlas; -struct scenery_editor final -{ - struct pair final { - std::shared_ptr<anim_atlas> atlas; - scenery s; - }; - - scenery_editor() noexcept; - - void set_rotation(rotation r); - void rotation() const; - void next_rotation(); - void prev_rotation(); - - void select_tile(const std::shared_ptr<anim_atlas>& atlas, enum rotation r, std::uint16_t frame); - void clear_selection(); - -private: - void load_atlases(); - - std::map<StringView, std::shared_ptr<anim_atlas>> _atlases; - pair _selected_frame; -}; - struct editor final { [[nodiscard]] bool dirty() const noexcept { return _dirty; } diff --git a/editor/precomp.hpp b/editor/precomp.hpp index f309133a..93ff8164 100644 --- a/editor/precomp.hpp +++ b/editor/precomp.hpp @@ -8,6 +8,7 @@ #include <Magnum/Math/Color.h> #include <Magnum/GL/DebugOutput.h> #include <Magnum/GL/Renderer.h> -#include <Magnum/Platform/Sdl2Application.h> #include <Magnum/ImGuiIntegration/Context.h> - +#if __has_include(<SDL.h>) +#include <Magnum/Platform/Sdl2Application.h> +#endif diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp new file mode 100644 index 00000000..c3b29c9d --- /dev/null +++ b/editor/scenery-editor.cpp @@ -0,0 +1,40 @@ +#include "scenery-editor.hpp" +#include "src/anim-atlas.hpp" + +namespace floormat { + +using rotation_ = enum rotation; +using rotation_t = std::underlying_type_t<rotation_>; + +scenery_editor::scenery_editor() noexcept +{ +} + +void scenery_editor::set_rotation(enum rotation r) +{ + _selected.s.r = r; +} + +rotation scenery_editor::rotation() const +{ + return _selected.s.r; +} + +void scenery_editor::next_rotation() +{ + auto r_1 = (rotation_t)_selected.s.r + 1; + auto rot = (rotation_)r_1; + if (rot >= rotation_::COUNT) + rot = (rotation_)0; + _selected.s.r = rot; +} + +void scenery_editor::prev_rotation() +{ + if (_selected.s.r == (rotation_)0) + _selected.s.r = (rotation_)((rotation_t)rotation_::COUNT - 1); + else + _selected.s.r = (rotation_)((rotation_t)_selected.s.r - 1); +} + +} // namespace floormat diff --git a/editor/scenery-editor.hpp b/editor/scenery-editor.hpp new file mode 100644 index 00000000..f4b40c66 --- /dev/null +++ b/editor/scenery-editor.hpp @@ -0,0 +1,37 @@ +#pragma once +#include "src/scenery.hpp" +#include <map> +#include <memory> +#include <Corrade/Containers/StringView.h> + +namespace floormat { + +struct anim_atlas; + +struct scenery_editor final +{ + struct pair final { + std::shared_ptr<anim_atlas> atlas; + scenery s; + }; + + scenery_editor() noexcept; + + void set_rotation(enum rotation r); + enum rotation rotation() const; + void next_rotation(); + void prev_rotation(); + + void select_tile(const std::shared_ptr<anim_atlas>& atlas, enum rotation r, std::uint16_t frame); + void clear_selection(); + bool is_atlas_selected() const; + bool is_item_selected(const std::shared_ptr<anim_atlas>& atlas, enum rotation r, std::uint16_t frame) const; + +private: + void load_atlases(); + + std::map<StringView, std::shared_ptr<anim_atlas>> _atlases; + pair _selected; +}; + +} // namespace floormat diff --git a/loader/loader-impl.cpp b/loader/loader-impl.cpp index 69a5f8ab..29234859 100644 --- a/loader/loader-impl.cpp +++ b/loader/loader-impl.cpp @@ -2,11 +2,17 @@ #include "src/tile-atlas.hpp" #include "compat/assert.hpp" #include "compat/alloca.hpp" +#include "src/anim-atlas.hpp" +#include "serialize/json-helper.hpp" +#include "serialize/anim.hpp" #include <filesystem> #include <unordered_map> #include <utility> #include <optional> +#include <Corrade/Containers/ArrayViewStl.h> +#include <Corrade/Containers/StringView.h> #include <Corrade/Containers/StringStlView.h> +#include <Corrade/Containers/StringStlHash.h> #include <Corrade/PluginManager/PluginManager.h> #include <Corrade/Utility/Resource.h> #include <Corrade/Utility/Path.h> @@ -21,6 +27,8 @@ using StringView = Corrade::Containers::StringView; +namespace Path = Corrade::Utility::Path; + namespace floormat { struct loader_impl final : loader_ @@ -32,11 +40,17 @@ struct loader_impl final : loader_ PluginManager::Manager<Trade::AbstractImageConverter> image_converter_plugins; - std::unordered_map<std::string, std::shared_ptr<struct tile_atlas>> atlas_map; + std::unordered_map<std::string, std::shared_ptr<struct tile_atlas>> tile_atlas_map; + std::unordered_map<StringView, std::shared_ptr<struct anim_atlas>> anim_atlas_map; + std::vector<String> anim_atlases; StringView shader(StringView filename) override; Trade::ImageData2D tile_texture(StringView filename) override; std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) override; + ArrayView<String> anim_atlas_list() override; + std::shared_ptr<struct anim_atlas> anim_atlas(StringView name) override; + + void get_anim_atlas_list(); static void set_application_working_directory(); @@ -56,31 +70,31 @@ StringView loader_impl::shader(StringView filename) std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub size) { - auto it = std::find_if(atlas_map.begin(), atlas_map.end(), [&](const auto& x) { + auto it = std::find_if(tile_atlas_map.cbegin(), tile_atlas_map.cend(), [&](const auto& x) { const auto& [k, v] = x; return StringView{k} == name; }); - if (it != atlas_map.end()) + if (it != tile_atlas_map.cend()) return it->second; auto image = tile_texture(name); auto atlas = std::make_shared<struct tile_atlas>(name, image, size); - atlas_map[name] = atlas; + tile_atlas_map[name] = atlas; return atlas; } Trade::ImageData2D loader_impl::tile_texture(StringView filename_) { - static_assert(IMAGE_PATH[sizeof(IMAGE_PATH)-2] == '/'); + static_assert(FM_IMAGE_PATH[sizeof(FM_IMAGE_PATH)-2] == '/'); fm_assert(filename_.size() < 4096); fm_assert(filename_.find('\\') == filename_.end()); fm_assert(filename_.find('\0') == 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); + char* const filename = (char*)alloca(filename_.size() + std::size(FM_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::size_t off = std::size(FM_IMAGE_PATH)-1; + std::memcpy(filename, FM_IMAGE_PATH, off); std::memcpy(filename + off, filename_.cbegin(), filename_.size()); return off + filename_.size(); ); @@ -89,7 +103,7 @@ Trade::ImageData2D loader_impl::tile_texture(StringView filename_) { std::memcpy(filename + len, extension.data(), extension.size()); filename[len + extension.size()] = '\0'; - if (Utility::Path::exists(filename) && tga_importer->openFile(filename)) + if (Path::exists(filename) && tga_importer->openFile(filename)) { auto img = tga_importer->image2D(0); if (!img) @@ -102,11 +116,53 @@ Trade::ImageData2D loader_impl::tile_texture(StringView filename_) fm_warn("can't open '%s'", filename); } } - const auto path = Utility::Path::currentDirectory(); + const auto path = Path::currentDirectory(); filename[len] = '\0'; fm_abort("can't open tile image '%s' (cwd '%s')", filename, path ? path->data() : "(null)"); } +ArrayView<String> loader_impl::anim_atlas_list() +{ + if (anim_atlases.empty()) + get_anim_atlas_list(); + return anim_atlases; +} + +std::shared_ptr<anim_atlas> loader_impl::anim_atlas(StringView name) +{ + if (auto it = anim_atlas_map.find(name); it != anim_atlas_map.end()) + return it->second; + else + { + const auto path = Path::join(FM_ANIM_PATH, name); + std::filesystem::path p = std::string_view{path}; + auto anim_info = json_helper::from_json<Serialize::anim>(p); + p.replace_extension({}); + auto tex = tile_texture(path); + + fm_assert(!anim_info.anim_name.isEmpty() && !anim_info.object_name.isEmpty()); + fm_assert(anim_info.pixel_size.product() > 0); + fm_assert(!anim_info.groups.empty()); + fm_assert(anim_info.nframes > 0); + fm_assert(anim_info.nframes == 1 || anim_info.fps > 0); + + auto atlas = std::make_shared<struct anim_atlas>(p.string(), tex, std::move(anim_info)); + return anim_atlas_map[atlas->name()] = atlas; + } +} + +void loader_impl::get_anim_atlas_list() +{ + anim_atlases.clear(); + anim_atlases.reserve(64); + using f = Path::ListFlag; + constexpr auto flags = f::SkipDirectories | f::SkipDotAndDotDot | f::SkipSpecial | f::SortAscending; + if (const auto list = Path::list(FM_ANIM_PATH, flags); list) + for (StringView str : *list) + if (str.hasSuffix(".json")) + anim_atlases.emplace_back(str.exceptSuffix(std::size(".json")-1)); +} + void loader_::destroy() { loader.~loader_(); @@ -119,7 +175,7 @@ void loader_impl::set_application_working_directory() if (once) return; once = true; - const auto location = Utility::Path::executableLocation(); + const auto location = Path::executableLocation(); if (!location) return; std::filesystem::path path((std::string)*location); diff --git a/main/precomp.hpp b/main/precomp.hpp index 68e8c965..8940421a 100644 --- a/main/precomp.hpp +++ b/main/precomp.hpp @@ -10,9 +10,9 @@ #include <Magnum/GL/Framebuffer.h> #include <Magnum/GL/Renderbuffer.h> #include <Magnum/GL/RenderbufferFormat.h> -#include <Magnum/Platform/Sdl2Application.h> #if __has_include(<SDL.h>) +#include <Magnum/Platform/Sdl2Application.h> #include <SDL_keycode.h> #include <SDL_events.h> #endif diff --git a/src/anim-atlas.cpp b/src/anim-atlas.cpp index 65b0038c..1aadab21 100644 --- a/src/anim-atlas.cpp +++ b/src/anim-atlas.cpp @@ -1,5 +1,6 @@ #include "anim-atlas.hpp" #include <Corrade/Containers/StringStlView.h> +#include <Magnum/GL/TextureFormat.h> namespace floormat { @@ -28,10 +29,17 @@ decltype(anim_atlas::_group_indices) anim_atlas::make_group_indices(const anim_i } anim_atlas::anim_atlas() noexcept = default; -anim_atlas::anim_atlas(StringView name, GL::Texture2D&& tex, anim_info info) noexcept : - _tex{std::move(tex)}, _name{name}, +anim_atlas::anim_atlas(StringView name, const ImageView2D& image, anim_info info) noexcept : + _name{name}, _info{std::move(info)}, _group_indices{make_group_indices(_info)} { + _tex.setWrapping(GL::SamplerWrapping::ClampToEdge) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setMinificationFilter(GL::SamplerFilter::Linear) + .setMaxAnisotropy(1) + .setBorderColor(Color4{1, 0, 0, 1}) + .setStorage(1, GL::textureFormat(image.format()), image.size()) + .setSubImage(0, {}, image); } anim_atlas::~anim_atlas() noexcept = default; @@ -74,4 +82,6 @@ auto anim_atlas::frame_texcoords(const anim_frame& frame) const noexcept -> texc }}; } + + } // namespace floormat diff --git a/src/anim-atlas.hpp b/src/anim-atlas.hpp index 4e73f9c8..a7553c5c 100644 --- a/src/anim-atlas.hpp +++ b/src/anim-atlas.hpp @@ -5,6 +5,7 @@ #include <array> #include <Corrade/Containers/String.h> #include <Magnum/Math/Vector2.h> +#include <Magnum/ImageView.h> #include <Magnum/GL/Texture.h> namespace floormat { @@ -17,7 +18,7 @@ struct anim_atlas final using texcoords = std::array<Vector2, 4>; anim_atlas() noexcept; - anim_atlas(StringView name, GL::Texture2D&& tex, anim_info info) noexcept; + anim_atlas(StringView name, const ImageView2D& tex, anim_info info) noexcept; ~anim_atlas() noexcept; anim_atlas(anim_atlas&&) noexcept; diff --git a/src/loader.hpp b/src/loader.hpp index 9dae4b11..0aaaa42e 100644 --- a/src/loader.hpp +++ b/src/loader.hpp @@ -1,20 +1,25 @@ #pragma once #include <memory> +#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/StringView.h> #include <Magnum/Trade/ImageData.h> -#define IMAGE_PATH "share/floormat/images/" +#define FM_IMAGE_PATH "share/floormat/images/" +#define FM_ANIM_PATH "share/floormat/anim/" namespace floormat { struct tile_atlas; +struct anim_atlas; struct loader_ { - virtual StringView shader(Containers::StringView filename) = 0; - virtual Trade::ImageData2D tile_texture(Containers::StringView filename) = 0; - virtual std::shared_ptr<struct tile_atlas> tile_atlas(Containers::StringView filename, Vector2ub size) = 0; + virtual StringView shader(StringView filename) = 0; + virtual Trade::ImageData2D tile_texture(StringView filename) = 0; + virtual std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) = 0; + virtual ArrayView<String> anim_atlas_list() = 0; + virtual std::shared_ptr<struct anim_atlas> anim_atlas(StringView name) = 0; static void destroy(); loader_(const loader_&) = delete; diff --git a/src/scenery.hpp b/src/scenery.hpp index 731b999b..1b0dc673 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -13,10 +13,17 @@ struct scenery final { using frame_t = std::uint16_t; - frame_t frame : 13 = 0; - rotation r : 3 = rotation::N; + frame_t frame : 12 = (1 << 12) - 1; + rotation r : 4 = rotation::N; + + constexpr operator bool() const noexcept; }; static_assert(sizeof(scenery) == sizeof(std::uint16_t)); +constexpr scenery::operator bool() const noexcept +{ + return frame == (1 << 13) - 1; +} + } // namespace floormat |