diff --git a/headers/enduro2d/high/_all.hpp b/headers/enduro2d/high/_all.hpp index bae45e74..c606f84f 100644 --- a/headers/enduro2d/high/_all.hpp +++ b/headers/enduro2d/high/_all.hpp @@ -30,6 +30,9 @@ #include "systems/render_system.hpp" +#include "address.hpp" +#include "asset.hpp" +#include "asset.inl" #include "atlas.hpp" #include "flipbook.hpp" #include "library.hpp" diff --git a/headers/enduro2d/high/_high.hpp b/headers/enduro2d/high/_high.hpp index b87bfda1..fe744a79 100644 --- a/headers/enduro2d/high/_high.hpp +++ b/headers/enduro2d/high/_high.hpp @@ -44,14 +44,14 @@ namespace e2d template < typename Asset, typename Content > class content_asset; - class content_asset_base; - - class library; + class asset; template < typename T > class asset_cache; class asset_cache_base; + class library; + class atlas; class flipbook; class model; diff --git a/headers/enduro2d/high/address.hpp b/headers/enduro2d/high/address.hpp new file mode 100644 index 00000000..46a00ba6 --- /dev/null +++ b/headers/enduro2d/high/address.hpp @@ -0,0 +1,15 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#pragma once + +#include "_high.hpp" + +namespace e2d { namespace address +{ + str parent(str_view address); + str nested(str_view address); +}} diff --git a/headers/enduro2d/high/asset.hpp b/headers/enduro2d/high/asset.hpp new file mode 100644 index 00000000..39ffd6ca --- /dev/null +++ b/headers/enduro2d/high/asset.hpp @@ -0,0 +1,148 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#ifndef E2D_INCLUDE_GUARD_1122A7CA62954AEF9E0A787064D28F73 +#define E2D_INCLUDE_GUARD_1122A7CA62954AEF9E0A787064D28F73 +#pragma once + +#include "_high.hpp" + +namespace e2d +{ + // + // asset_loading_exception + // + + class asset_loading_exception : public exception { + const char* what() const noexcept override { + return "asset loading exception"; + } + }; + + // + // bad_asset_factory_operation + // + + class bad_asset_factory_operation final : public exception { + public: + const char* what() const noexcept final { + return "bad asset factory operation"; + } + }; + + // + // asset + // + + class asset; + using asset_ptr = intrusive_ptr; + using nested_content = hash_map; + + class asset + : private noncopyable + , public ref_counter { + public: + asset(); + virtual ~asset() noexcept; + virtual asset_ptr find_nested_asset(str_view name) const noexcept = 0; + }; + + // + // content_asset + // + + template < typename Asset, typename Content > + class content_asset : public asset { + public: + using asset_type = Asset; + using content_type = Content; + + using ptr = intrusive_ptr; + using load_result = intrusive_ptr; + using load_async_result = stdex::promise; + public: + static load_result create(); + static load_result create(Content content); + static load_result create(Content content, nested_content nested_content); + + void fill(Content content); + void fill(Content content, nested_content nested_content); + + const Content& content() const noexcept; + + template < typename T > + intrusive_ptr find_nested_asset(str_view name) const noexcept; + asset_ptr find_nested_asset(str_view name) const noexcept override; + private: + Content content_; + nested_content nested_content_; + }; + + // + // asset_cache_base + // + + class asset_cache_base : private noncopyable { + public: + asset_cache_base(); + virtual ~asset_cache_base() noexcept; + + static std::size_t unload_all_unused_assets() noexcept; + virtual std::size_t unload_self_unused_assets() noexcept = 0; + private: + static std::mutex mutex_; + static hash_set caches_; + }; + + // + // asset_cache + // + + template < typename Asset > + class asset_cache : public asset_cache_base + , public module> { + public: + using asset_ptr = typename Asset::ptr; + public: + asset_cache(library& l); + ~asset_cache() noexcept final; + + asset_ptr find(str_hash address) const noexcept; + void store(str_hash address, const asset_ptr& asset); + + void clear() noexcept; + std::size_t asset_count() const noexcept; + + std::size_t unload_self_unused_assets() noexcept override; + private: + library& library_; + mutable std::mutex mutex_; + hash_map assets_; + }; + + // + // asset_factory + // + + class asset_factory : public module { + public: + using asset_creator = std::function< + stdex::promise(const library& library, str_view address)>; + public: + asset_factory(); + ~asset_factory() noexcept final; + + template < typename Asset > + asset_factory& register_asset(str_hash type); + asset_factory& register_creator(str_hash type, asset_creator creator); + private: + std::mutex mutex_; + hash_map creators_; + }; +} + +#include "asset.inl" +#endif diff --git a/headers/enduro2d/high/asset.inl b/headers/enduro2d/high/asset.inl new file mode 100644 index 00000000..801e0b08 --- /dev/null +++ b/headers/enduro2d/high/asset.inl @@ -0,0 +1,150 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#ifndef E2D_INCLUDE_GUARD_6FD0B1DD12004CF78E7AC5FBBC36E854 +#define E2D_INCLUDE_GUARD_6FD0B1DD12004CF78E7AC5FBBC36E854 +#pragma once + +#include "_high.hpp" +#include "asset.hpp" + +namespace e2d +{ + // + // content_asset + // + + template < typename Asset, typename Content > + typename content_asset::load_result + content_asset::create() { + return load_result(new Asset()); + } + + template < typename Asset, typename Content > + typename content_asset::load_result + content_asset::create(Content content) { + auto result = create(); + result->fill(std::move(content)); + return result; + } + + template < typename Asset, typename Content > + typename content_asset::load_result + content_asset::create(Content content, nested_content nested_content) { + auto result = create(); + result->fill(std::move(content), std::move(nested_content)); + return result; + } + + template < typename Asset, typename Content > + void content_asset::fill(Content content) { + content_ = std::move(content); + } + + template < typename Asset, typename Content > + void content_asset::fill(Content content, nested_content nested_content) { + content_ = std::move(content); + nested_content_ = std::move(nested_content); + } + + template < typename Asset, typename Content > + const Content& content_asset::content() const noexcept { + return content_; + } + + template < typename Asset, typename Content > + template < typename T > + intrusive_ptr content_asset::find_nested_asset(str_view name) const noexcept { + return dynamic_pointer_cast(find_nested_asset(name)); + } + + template < typename Asset, typename Content > + asset_ptr content_asset::find_nested_asset(str_view name) const noexcept { + const auto iter = nested_content_.find(name); + return iter != nested_content_.end() + ? iter->second + : nullptr; + } + + // + // asset_cache + // + + template < typename T > + asset_cache::asset_cache(library& l) + : library_(l) {} + + template < typename T > + asset_cache::~asset_cache() noexcept = default; + + template < typename T > + typename asset_cache::asset_ptr asset_cache::find(str_hash address) const noexcept { + std::lock_guard guard(mutex_); + const auto iter = assets_.find(address); + return iter != assets_.end() + ? iter->second + : nullptr; + } + + template < typename T > + void asset_cache::store(str_hash address, const asset_ptr& asset) { + std::lock_guard guard(mutex_); + assets_[address] = asset; + } + + template < typename T > + void asset_cache::clear() noexcept { + std::lock_guard guard(mutex_); + assets_.clear(); + } + + template < typename T > + std::size_t asset_cache::asset_count() const noexcept { + std::lock_guard guard(mutex_); + return assets_.size(); + } + + template < typename T > + std::size_t asset_cache::unload_self_unused_assets() noexcept { + std::lock_guard guard(mutex_); + std::size_t result = 0u; + for ( auto iter = assets_.begin(); iter != assets_.end(); ) { + if ( !iter->second || 1 == iter->second->use_count() ) { + iter = assets_.erase(iter); + ++result; + } else { + ++iter; + } + } + return result; + } + + // + // asset_factory + // + + template < typename Asset > + asset_factory& asset_factory::register_asset(str_hash type) { + return register_creator(type, [](const library& library, str_view address) { + return Asset::load_async(library, address) + .then([](const typename Asset::load_result& result){ + return static_pointer_cast(result); + }); + }); + } + + inline asset_factory& asset_factory::register_creator(str_hash type, asset_creator creator) { + std::lock_guard guard(mutex_); + bool success = creators_.insert( + std::make_pair(type, std::move(creator))).second; + if ( !success ) { + throw bad_asset_factory_operation(); + } + return *this; + } +} + +#endif diff --git a/headers/enduro2d/high/assets/atlas_asset.hpp b/headers/enduro2d/high/assets/atlas_asset.hpp index c333d181..38b268df 100644 --- a/headers/enduro2d/high/assets/atlas_asset.hpp +++ b/headers/enduro2d/high/assets/atlas_asset.hpp @@ -8,15 +8,13 @@ #include "../_high.hpp" -#include "../atlas.hpp" #include "../library.hpp" +#include "../atlas.hpp" namespace e2d { class atlas_asset final : public content_asset { public: - atlas_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/binary_asset.hpp b/headers/enduro2d/high/assets/binary_asset.hpp index 612c5d25..17e40b95 100644 --- a/headers/enduro2d/high/assets/binary_asset.hpp +++ b/headers/enduro2d/high/assets/binary_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class binary_asset final : public content_asset { public: - binary_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/flipbook_asset.hpp b/headers/enduro2d/high/assets/flipbook_asset.hpp index 62c4c657..e9bd17d1 100644 --- a/headers/enduro2d/high/assets/flipbook_asset.hpp +++ b/headers/enduro2d/high/assets/flipbook_asset.hpp @@ -8,15 +8,13 @@ #include "../_high.hpp" -#include "../flipbook.hpp" #include "../library.hpp" +#include "../flipbook.hpp" namespace e2d { class flipbook_asset final : public content_asset { public: - flipbook_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/image_asset.hpp b/headers/enduro2d/high/assets/image_asset.hpp index 6d2f5f5c..99d88690 100644 --- a/headers/enduro2d/high/assets/image_asset.hpp +++ b/headers/enduro2d/high/assets/image_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class image_asset final : public content_asset { public: - image_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/material_asset.hpp b/headers/enduro2d/high/assets/material_asset.hpp index d0c1bc76..7d59e4d9 100644 --- a/headers/enduro2d/high/assets/material_asset.hpp +++ b/headers/enduro2d/high/assets/material_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class material_asset final : public content_asset { public: - material_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/mesh_asset.hpp b/headers/enduro2d/high/assets/mesh_asset.hpp index 074ef114..0fc294e5 100644 --- a/headers/enduro2d/high/assets/mesh_asset.hpp +++ b/headers/enduro2d/high/assets/mesh_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class mesh_asset final : public content_asset { public: - mesh_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/model_asset.hpp b/headers/enduro2d/high/assets/model_asset.hpp index c60f8db6..dc2cbb57 100644 --- a/headers/enduro2d/high/assets/model_asset.hpp +++ b/headers/enduro2d/high/assets/model_asset.hpp @@ -8,15 +8,13 @@ #include "../_high.hpp" -#include "../model.hpp" #include "../library.hpp" +#include "../model.hpp" namespace e2d { class model_asset final : public content_asset { public: - model_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/shader_asset.hpp b/headers/enduro2d/high/assets/shader_asset.hpp index ffde6928..a79cd031 100644 --- a/headers/enduro2d/high/assets/shader_asset.hpp +++ b/headers/enduro2d/high/assets/shader_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class shader_asset final : public content_asset { public: - shader_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/shape_asset.hpp b/headers/enduro2d/high/assets/shape_asset.hpp index 4c7bd758..f949f41d 100644 --- a/headers/enduro2d/high/assets/shape_asset.hpp +++ b/headers/enduro2d/high/assets/shape_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class shape_asset final : public content_asset { public: - shape_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/sprite_asset.hpp b/headers/enduro2d/high/assets/sprite_asset.hpp index f00f2f9c..86ed8f20 100644 --- a/headers/enduro2d/high/assets/sprite_asset.hpp +++ b/headers/enduro2d/high/assets/sprite_asset.hpp @@ -8,15 +8,13 @@ #include "../_high.hpp" -#include "../sprite.hpp" #include "../library.hpp" +#include "../sprite.hpp" namespace e2d { class sprite_asset final : public content_asset { public: - sprite_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/text_asset.hpp b/headers/enduro2d/high/assets/text_asset.hpp index 9e001684..49a3f3da 100644 --- a/headers/enduro2d/high/assets/text_asset.hpp +++ b/headers/enduro2d/high/assets/text_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class text_asset final : public content_asset { public: - text_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/assets/texture_asset.hpp b/headers/enduro2d/high/assets/texture_asset.hpp index 50f4157f..6715490b 100644 --- a/headers/enduro2d/high/assets/texture_asset.hpp +++ b/headers/enduro2d/high/assets/texture_asset.hpp @@ -7,14 +7,13 @@ #pragma once #include "../_high.hpp" + #include "../library.hpp" namespace e2d { class texture_asset final : public content_asset { public: - texture_asset(content_type content) - : content_asset(std::move(content)) {} - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/headers/enduro2d/high/library.hpp b/headers/enduro2d/high/library.hpp index a1f50eaf..72f81716 100644 --- a/headers/enduro2d/high/library.hpp +++ b/headers/enduro2d/high/library.hpp @@ -10,6 +10,9 @@ #include "_high.hpp" +#include "asset.hpp" +#include "address.hpp" + namespace e2d { // @@ -23,54 +26,6 @@ namespace e2d } }; - // - // asset_loading_exception - // - - class asset_loading_exception : public exception { - const char* what() const noexcept override = 0; - }; - - // - // content_asset_base - // - - class content_asset_base - : private noncopyable - , public ref_counter { - public: - content_asset_base() = default; - virtual ~content_asset_base() noexcept = default; - }; - - // - // content_asset - // - - template < typename Asset, typename Content > - class content_asset : public content_asset_base { - public: - using asset_type = Asset; - using content_type = Content; - - using ptr = intrusive_ptr; - using load_result = intrusive_ptr; - using load_async_result = stdex::promise; - public: - static load_result create(Content content) { - return load_result(new Asset(std::move(content))); - } - - content_asset(Content content) - : content_(std::move(content)) {} - - const Content& content() const noexcept { - return content_; - } - private: - Content content_; - }; - // // library // @@ -84,55 +39,19 @@ namespace e2d std::size_t unload_unused_assets() noexcept; template < typename Asset > - typename Asset::load_result load_asset(str_view address); + typename Asset::load_result load_main_asset(str_view address) const; template < typename Asset > - typename Asset::load_async_result load_asset_async(str_view address); + typename Asset::load_async_result load_main_asset_async(str_view address) const; + + template < typename Asset, typename Nested = Asset > + typename Nested::load_result load_asset(str_view address) const; + + template < typename Asset, typename Nested = Asset > + typename Nested::load_async_result load_asset_async(str_view address) const; private: url root_; }; - - // - // asset_cache_base - // - - class asset_cache_base : private noncopyable { - public: - asset_cache_base(); - virtual ~asset_cache_base() noexcept; - - static std::size_t unload_all_unused_assets() noexcept; - virtual std::size_t unload_self_unused_assets() noexcept = 0; - private: - static std::mutex mutex_; - static hash_set caches_; - }; - - // - // asset_cache - // - - template < typename Asset > - class asset_cache : public asset_cache_base - , public module> { - public: - using asset_result = typename Asset::load_result; - public: - asset_cache(library& l); - ~asset_cache() noexcept final; - - asset_result find(str_hash address) const; - void store(str_hash address, const asset_result& asset); - - void clear() noexcept; - std::size_t asset_count() const noexcept; - - std::size_t unload_self_unused_assets() noexcept override; - private: - library& library_; - mutable std::mutex mutex_; - hash_map assets_; - }; } #include "library.inl" diff --git a/headers/enduro2d/high/library.inl b/headers/enduro2d/high/library.inl index 8d01792e..edf4b579 100644 --- a/headers/enduro2d/high/library.inl +++ b/headers/enduro2d/high/library.inl @@ -13,13 +13,9 @@ namespace e2d { - // - // library - // - template < typename Asset > - typename Asset::load_result library::load_asset(str_view address) { - auto p = load_asset_async(address); + typename Asset::load_result library::load_main_asset(str_view address) const { + auto p = load_main_asset_async(address); if ( modules::is_initialized() ) { the().active_safe_wait_promise(p); @@ -29,77 +25,61 @@ namespace e2d } template < typename Asset > - typename Asset::load_async_result library::load_asset_async(str_view address) { + typename Asset::load_async_result library::load_main_asset_async(str_view address) const { + const auto main_address = address::parent(address); + const auto main_address_hash = make_hash(main_address); + if ( !modules::is_initialized>() ) { - return Asset::load_async(*this, address); + return Asset::load_async(*this, main_address); } auto& cache = the>(); - if ( auto cached_asset = cache.find(address) ) { + if ( auto cached_asset = cache.find(main_address_hash) ) { return stdex::make_resolved_promise(std::move(cached_asset)); } - return Asset::load_async(*this, address) + return Asset::load_async(*this, main_address) .then([ &cache, - address_hash = make_hash(address) - ](auto&& new_asset){ - cache.store(address_hash, new_asset); - return std::forward(new_asset); + main_address_hash + ](const typename Asset::load_result& new_asset){ + cache.store(main_address_hash, new_asset); + return new_asset; }); } - // - // asset_cache - // + template < typename Asset, typename Nested > + typename Nested::load_result library::load_asset(str_view address) const { + auto p = load_asset_async(address); - template < typename T > - asset_cache::asset_cache(library& l) - : library_(l) {} - - template < typename T > - asset_cache::~asset_cache() noexcept = default; - - template < typename T > - typename asset_cache::asset_result asset_cache::find(str_hash address) const { - std::lock_guard guard(mutex_); - const auto iter = assets_.find(address); - return iter != assets_.end() - ? iter->second - : nullptr; - } - - template < typename T > - void asset_cache::store(str_hash address, const asset_result& asset) { - std::lock_guard guard(mutex_); - assets_[address] = asset; - } - - template < typename T > - void asset_cache::clear() noexcept { - std::lock_guard guard(mutex_); - assets_.clear(); - } - - template < typename T > - std::size_t asset_cache::asset_count() const noexcept { - std::lock_guard guard(mutex_); - return assets_.size(); - } - - template < typename T > - std::size_t asset_cache::unload_self_unused_assets() noexcept { - std::lock_guard guard(mutex_); - std::size_t result = 0u; - for ( auto iter = assets_.begin(); iter != assets_.end(); ) { - if ( !iter->second || 1 == iter->second->use_count() ) { - iter = assets_.erase(iter); - ++result; - } else { - ++iter; - } + if ( modules::is_initialized() ) { + the().active_safe_wait_promise(p); } - return result; + + return p.get_or_default(nullptr); + } + + template < typename Asset, typename Nested > + typename Nested::load_async_result library::load_asset_async(str_view address) const { + return load_main_asset_async(address::parent(address)) + .then([ + address = str(address) + ](const typename Asset::load_result& main_asset){ + asset_ptr nested_asset = main_asset; + str nested_address = address::nested(address); + + while ( nested_asset && !nested_address.empty() ) { + nested_asset = nested_asset->find_nested_asset(address::parent(nested_address)); + nested_address = address::nested(nested_address); + } + + using nested_asset_type = typename Nested::asset_type; + if ( auto result = dynamic_pointer_cast(nested_asset) ) { + return result; + } + + throw asset_loading_exception(); + }); } } diff --git a/headers/enduro2d/high/sprite.hpp b/headers/enduro2d/high/sprite.hpp index 3b9d074a..f1d178f8 100644 --- a/headers/enduro2d/high/sprite.hpp +++ b/headers/enduro2d/high/sprite.hpp @@ -40,7 +40,6 @@ namespace e2d const texture_asset::ptr& texture() const noexcept; const material_asset::ptr& material() const noexcept; private: - v2f size_; v2f pivot_; b2f texrect_; texture_asset::ptr texture_; diff --git a/sources/enduro2d/high/address.cpp b/sources/enduro2d/high/address.cpp new file mode 100644 index 00000000..c676c3c7 --- /dev/null +++ b/sources/enduro2d/high/address.cpp @@ -0,0 +1,39 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#include + +namespace +{ + using namespace e2d; + + const str_view address_separator = ":/"; + + str_view::iterator str_view_search(str_view str, str_view s_str) noexcept { + return std::search(str.begin(), str.end(), s_str.begin(), s_str.end()); + } +} + +namespace e2d { namespace address +{ + str parent(str_view address) { + const auto sep_e = str_view_search(address, address_separator); + if ( sep_e == address.end() ) { + return address; + } + const auto sep_d = std::distance(address.begin(), sep_e); + return address.substr(0, static_cast(sep_d)); + } + + str nested(str_view address) { + const auto sep_e = str_view_search(address, address_separator); + if ( sep_e == address.end() ) { + return str(); + } + const auto sep_d = std::distance(address.begin(), sep_e); + return address.substr(static_cast(sep_d) + address_separator.size()); + } +}} diff --git a/sources/enduro2d/high/asset.cpp b/sources/enduro2d/high/asset.cpp new file mode 100644 index 00000000..25d77626 --- /dev/null +++ b/sources/enduro2d/high/asset.cpp @@ -0,0 +1,49 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#include + +namespace e2d +{ + // + // asset + // + + asset::asset() = default; + asset::~asset() noexcept = default; + + // + // asset_cache_base + // + + std::mutex asset_cache_base::mutex_; + hash_set asset_cache_base::caches_; + + asset_cache_base::asset_cache_base() { + std::lock_guard guard(mutex_); + caches_.insert(this); + } + + asset_cache_base::~asset_cache_base() noexcept { + std::lock_guard guard(mutex_); + caches_.erase(this); + } + + std::size_t asset_cache_base::unload_all_unused_assets() noexcept { + std::lock_guard guard(mutex_); + return std::accumulate(caches_.begin(), caches_.end(), std::size_t(0), + [](std::size_t acc, asset_cache_base* cache){ + return acc + cache->unload_self_unused_assets(); + }); + } + + // + // asset_factory + // + + asset_factory::asset_factory() = default; + asset_factory::~asset_factory() noexcept = default; +} diff --git a/sources/enduro2d/high/assets/atlas_asset.cpp b/sources/enduro2d/high/assets/atlas_asset.cpp index a9e48c18..d800f71e 100644 --- a/sources/enduro2d/high/assets/atlas_asset.cpp +++ b/sources/enduro2d/high/assets/atlas_asset.cpp @@ -145,7 +145,7 @@ namespace } stdex::promise parse_atlas( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -187,7 +187,7 @@ namespace namespace e2d { atlas_asset::load_async_result atlas_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/binary_asset.cpp b/sources/enduro2d/high/assets/binary_asset.cpp index ed321b77..b989a25d 100644 --- a/sources/enduro2d/high/assets/binary_asset.cpp +++ b/sources/enduro2d/high/assets/binary_asset.cpp @@ -20,7 +20,7 @@ namespace namespace e2d { binary_asset::load_async_result binary_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { const auto asset_url = library.root() / address; return the().load_async(asset_url) diff --git a/sources/enduro2d/high/assets/flipbook_asset.cpp b/sources/enduro2d/high/assets/flipbook_asset.cpp index 3d71789c..d3a7c8d5 100644 --- a/sources/enduro2d/high/assets/flipbook_asset.cpp +++ b/sources/enduro2d/high/assets/flipbook_asset.cpp @@ -107,7 +107,7 @@ namespace } stdex::promise parse_flipbook_atlas_frame( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -140,7 +140,7 @@ namespace } stdex::promise parse_flipbook_texture_frame( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -174,7 +174,7 @@ namespace } stdex::promise parse_flipbook_frame( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -191,7 +191,7 @@ namespace } stdex::promise> parse_flipbook_frames( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -245,7 +245,7 @@ namespace } stdex::promise parse_flipbook( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -290,7 +290,7 @@ namespace namespace e2d { flipbook_asset::load_async_result flipbook_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/image_asset.cpp b/sources/enduro2d/high/assets/image_asset.cpp index a86f10bf..93747a15 100644 --- a/sources/enduro2d/high/assets/image_asset.cpp +++ b/sources/enduro2d/high/assets/image_asset.cpp @@ -21,7 +21,7 @@ namespace namespace e2d { image_asset::load_async_result image_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const binary_asset::load_result& image_data){ diff --git a/sources/enduro2d/high/assets/json_asset.cpp b/sources/enduro2d/high/assets/json_asset.cpp index 689d8fa2..bd53b749 100644 --- a/sources/enduro2d/high/assets/json_asset.cpp +++ b/sources/enduro2d/high/assets/json_asset.cpp @@ -22,7 +22,7 @@ namespace namespace e2d { json_asset::load_async_result json_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const text_asset::load_result& json_data){ diff --git a/sources/enduro2d/high/assets/json_asset.hpp b/sources/enduro2d/high/assets/json_asset.hpp index 60dd7ec1..f05e963b 100644 --- a/sources/enduro2d/high/assets/json_asset.hpp +++ b/sources/enduro2d/high/assets/json_asset.hpp @@ -15,6 +15,6 @@ namespace e2d class json_asset final : public content_asset { public: using content_asset::content_asset; - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/sources/enduro2d/high/assets/material_asset.cpp b/sources/enduro2d/high/assets/material_asset.cpp index 02c96e53..9b8d979f 100644 --- a/sources/enduro2d/high/assets/material_asset.cpp +++ b/sources/enduro2d/high/assets/material_asset.cpp @@ -492,7 +492,7 @@ namespace } stdex::promise parse_shader_block( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -506,7 +506,7 @@ namespace } stdex::promise parse_texture_block( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -520,7 +520,7 @@ namespace } stdex::promise> parse_sampler_state( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -669,7 +669,7 @@ namespace } stdex::promise parse_property_block( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -1092,7 +1092,7 @@ namespace } stdex::promise parse_pass_state( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -1126,7 +1126,7 @@ namespace } stdex::promise parse_material( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -1169,7 +1169,7 @@ namespace namespace e2d { material_asset::load_async_result material_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/mesh_asset.cpp b/sources/enduro2d/high/assets/mesh_asset.cpp index 660a396b..7d7b90ea 100644 --- a/sources/enduro2d/high/assets/mesh_asset.cpp +++ b/sources/enduro2d/high/assets/mesh_asset.cpp @@ -21,7 +21,7 @@ namespace namespace e2d { mesh_asset::load_async_result mesh_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const binary_asset::load_result& mesh_data){ diff --git a/sources/enduro2d/high/assets/model_asset.cpp b/sources/enduro2d/high/assets/model_asset.cpp index 6f95b408..18fa6dd6 100644 --- a/sources/enduro2d/high/assets/model_asset.cpp +++ b/sources/enduro2d/high/assets/model_asset.cpp @@ -51,7 +51,7 @@ namespace } stdex::promise parse_model( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -97,7 +97,7 @@ namespace namespace e2d { model_asset::load_async_result model_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/shader_asset.cpp b/sources/enduro2d/high/assets/shader_asset.cpp index d9a66921..b77bc9d7 100644 --- a/sources/enduro2d/high/assets/shader_asset.cpp +++ b/sources/enduro2d/high/assets/shader_asset.cpp @@ -49,7 +49,7 @@ namespace } stdex::promise parse_shader( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -84,7 +84,7 @@ namespace namespace e2d { shader_asset::load_async_result shader_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/shape_asset.cpp b/sources/enduro2d/high/assets/shape_asset.cpp index b19abcf2..69495697 100644 --- a/sources/enduro2d/high/assets/shape_asset.cpp +++ b/sources/enduro2d/high/assets/shape_asset.cpp @@ -21,7 +21,7 @@ namespace namespace e2d { shape_asset::load_async_result shape_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const binary_asset::load_result& shape_data){ diff --git a/sources/enduro2d/high/assets/sprite_asset.cpp b/sources/enduro2d/high/assets/sprite_asset.cpp index 48e50e6d..debc72e7 100644 --- a/sources/enduro2d/high/assets/sprite_asset.cpp +++ b/sources/enduro2d/high/assets/sprite_asset.cpp @@ -78,7 +78,7 @@ namespace } stdex::promise parse_sprite_with_atlas( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -130,7 +130,7 @@ namespace } stdex::promise parse_sprite_with_texture( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -183,7 +183,7 @@ namespace } stdex::promise parse_sprite( - library& library, + const library& library, str_view parent_address, const rapidjson::Value& root) { @@ -203,7 +203,7 @@ namespace namespace e2d { sprite_asset::load_async_result sprite_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([ diff --git a/sources/enduro2d/high/assets/text_asset.cpp b/sources/enduro2d/high/assets/text_asset.cpp index ebd2db73..10a7b17e 100644 --- a/sources/enduro2d/high/assets/text_asset.cpp +++ b/sources/enduro2d/high/assets/text_asset.cpp @@ -20,7 +20,7 @@ namespace namespace e2d { text_asset::load_async_result text_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { const auto asset_url = library.root() / address; return the().load_as_string_async(asset_url) diff --git a/sources/enduro2d/high/assets/texture_asset.cpp b/sources/enduro2d/high/assets/texture_asset.cpp index 55430ef8..2bbbc066 100644 --- a/sources/enduro2d/high/assets/texture_asset.cpp +++ b/sources/enduro2d/high/assets/texture_asset.cpp @@ -21,7 +21,7 @@ namespace namespace e2d { texture_asset::load_async_result texture_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const image_asset::load_result& texture_data){ diff --git a/sources/enduro2d/high/assets/xml_asset.cpp b/sources/enduro2d/high/assets/xml_asset.cpp index 89e6f6ce..eba09db4 100644 --- a/sources/enduro2d/high/assets/xml_asset.cpp +++ b/sources/enduro2d/high/assets/xml_asset.cpp @@ -22,7 +22,7 @@ namespace namespace e2d { xml_asset::load_async_result xml_asset::load_async( - library& library, str_view address) + const library& library, str_view address) { return library.load_asset_async(address) .then([](const text_asset::load_result& xml_data){ diff --git a/sources/enduro2d/high/assets/xml_asset.hpp b/sources/enduro2d/high/assets/xml_asset.hpp index 6c640c54..2ffd45c3 100644 --- a/sources/enduro2d/high/assets/xml_asset.hpp +++ b/sources/enduro2d/high/assets/xml_asset.hpp @@ -15,6 +15,6 @@ namespace e2d class xml_asset final : public content_asset { public: using content_asset::content_asset; - static load_async_result load_async(library& library, str_view address); + static load_async_result load_async(const library& library, str_view address); }; } diff --git a/sources/enduro2d/high/library.cpp b/sources/enduro2d/high/library.cpp index 4fc83c1e..08e9ed1a 100644 --- a/sources/enduro2d/high/library.cpp +++ b/sources/enduro2d/high/library.cpp @@ -6,17 +6,8 @@ #include -namespace -{ - using namespace e2d; -} - namespace e2d { - // - // library - // - library::library(const url& root) : root_(root) {} @@ -29,29 +20,4 @@ namespace e2d std::size_t library::unload_unused_assets() noexcept { return asset_cache_base::unload_all_unused_assets(); } - - // - // asset_cache_base - // - - std::mutex asset_cache_base::mutex_; - hash_set asset_cache_base::caches_; - - asset_cache_base::asset_cache_base() { - std::lock_guard guard(mutex_); - caches_.insert(this); - } - - asset_cache_base::~asset_cache_base() noexcept { - std::lock_guard guard(mutex_); - caches_.erase(this); - } - - std::size_t asset_cache_base::unload_all_unused_assets() noexcept { - std::lock_guard guard(mutex_); - return std::accumulate( caches_.begin(), caches_.end(), std::size_t(0), - [](std::size_t acc, asset_cache_base* cache){ - return acc + cache->unload_self_unused_assets(); - }); - } } diff --git a/sources/enduro2d/high/sprite.cpp b/sources/enduro2d/high/sprite.cpp index 65676103..f8773757 100644 --- a/sources/enduro2d/high/sprite.cpp +++ b/sources/enduro2d/high/sprite.cpp @@ -28,7 +28,6 @@ namespace e2d } void sprite::clear() noexcept { - size_ = v2f::zero(); pivot_ = v2f::zero(); texrect_ = b2f::zero(); texture_.reset(); @@ -37,7 +36,6 @@ namespace e2d void sprite::swap(sprite& other) noexcept { using std::swap; - swap(size_, other.size_); swap(pivot_, other.pivot_); swap(texrect_, other.texrect_); swap(texture_, other.texture_); @@ -55,7 +53,6 @@ namespace e2d sprite& sprite::assign(const sprite& other) { if ( this != &other ) { sprite s; - s.size_ = other.size_; s.pivot_ = other.pivot_; s.texrect_ = other.texrect_; s.texture_ = other.texture_; diff --git a/sources/enduro2d/high/starter.cpp b/sources/enduro2d/high/starter.cpp index 060ae459..d9829fe6 100644 --- a/sources/enduro2d/high/starter.cpp +++ b/sources/enduro2d/high/starter.cpp @@ -28,10 +28,10 @@ namespace using namespace e2d; template < typename Module, typename... Args > - void safe_module_initialize(Args&&... args) { - if ( !modules::is_initialized() ) { - modules::initialize(std::forward(args)...); - } + Module& safe_module_initialize(Args&&... args) { + return modules::is_initialized() + ? modules::instance() + : modules::initialize(std::forward(args)...); } class starter_application final : public application { @@ -137,11 +137,24 @@ namespace e2d safe_module_initialize>(the()); safe_module_initialize>(the()); safe_module_initialize>(the()); + safe_module_initialize() + .register_asset("atlas") + .register_asset("binary") + .register_asset("image") + .register_asset("material") + .register_asset("mesh") + .register_asset("model") + .register_asset("shader") + .register_asset("shape") + .register_asset("sprite") + .register_asset("text") + .register_asset("texture"); safe_module_initialize(); } starter::~starter() noexcept { modules::shutdown(); + modules::shutdown(); modules::shutdown>(); modules::shutdown>(); modules::shutdown>(); diff --git a/untests/sources/untests_high/address.cpp b/untests/sources/untests_high/address.cpp new file mode 100644 index 00000000..231b6c60 --- /dev/null +++ b/untests/sources/untests_high/address.cpp @@ -0,0 +1,31 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#include "_high.hpp" +using namespace e2d; + +TEST_CASE("address") { + SECTION("parent") { + REQUIRE(address::parent("") == ""); + REQUIRE(address::parent(":/") == ""); + REQUIRE(address::parent(":/child") == ""); + REQUIRE(address::parent("at/las.json") == "at/las.json"); + REQUIRE(address::parent("at/las.json:/") == "at/las.json"); + REQUIRE(address::parent("at/las.json:/spr/ite.png") == "at/las.json"); + REQUIRE(address::parent("at/las.json:/spr/ite.png:/") == "at/las.json"); + REQUIRE(address::parent("at/las.json:/spr/ite.png:/child") == "at/las.json"); + } + SECTION("nested") { + REQUIRE(address::nested("") == ""); + REQUIRE(address::nested(":/") == ""); + REQUIRE(address::nested(":/chi/ld") == "chi/ld"); + REQUIRE(address::nested("at/las.json") == ""); + REQUIRE(address::nested("at/las.json:/") == ""); + REQUIRE(address::nested("at/las.json:/spr/ite.png") == "spr/ite.png"); + REQUIRE(address::nested("at/las.json:/spr/ite.png:/") == "spr/ite.png:/"); + REQUIRE(address::nested("at/las.json:/spr/ite.png:/chi/ld") == "spr/ite.png:/chi/ld"); + } +} diff --git a/untests/sources/untests_high/asset.cpp b/untests/sources/untests_high/asset.cpp new file mode 100644 index 00000000..26fe03db --- /dev/null +++ b/untests/sources/untests_high/asset.cpp @@ -0,0 +1,79 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019 Matvey Cherevko + ******************************************************************************/ + +#include "_high.hpp" +using namespace e2d; + +namespace +{ + class safe_starter_initializer final : private noncopyable { + public: + safe_starter_initializer() { + modules::initialize(0, nullptr, + starter::parameters( + engine::parameters("asset_untests", "enduro2d") + .without_graphics(true))); + } + + ~safe_starter_initializer() noexcept { + modules::shutdown(); + } + }; + + class fake_nested_asset final : public content_asset { + }; + + class fake_asset final : public content_asset { + public: + static load_async_result load_async(const library& library, str_view address) { + E2D_UNUSED(library); + return address == "42" + ? stdex::make_resolved_promise(fake_asset::create(42, { + {"21", fake_nested_asset::create(21, { + {"2", fake_nested_asset::create(2)} + })}, + {"84", fake_nested_asset::create(84, { + {"8", fake_nested_asset::create(8)} + })} + })) + : stdex::make_rejected_promise(asset_loading_exception()); + } + }; +} + +TEST_CASE("asset"){ + safe_starter_initializer initializer; + library& l = the(); + { + REQUIRE_FALSE(l.load_asset("none")); + + auto fa = l.load_asset("42"); + REQUIRE(fa); + REQUIRE(fa->content() == 42); + + REQUIRE_FALSE(fa->find_nested_asset("none")); + REQUIRE(fa->find_nested_asset("21")); + REQUIRE_FALSE(fa->find_nested_asset("21")); + REQUIRE(fa->find_nested_asset("21")); + REQUIRE(fa->find_nested_asset("21")->content() == 21); + REQUIRE(fa->find_nested_asset("84")->content() == 84); + } + { + REQUIRE(l.load_asset("42:/21")); + REQUIRE(l.load_asset("42:/21")->content() == 21); + + REQUIRE_FALSE(l.load_asset("42:/21")); + REQUIRE_FALSE(l.load_asset("42:/none")); + REQUIRE_FALSE(l.load_asset("42:/none:/21")); + + REQUIRE(l.load_asset("42:/21:/2")); + REQUIRE(l.load_asset("42:/21:/2")->content() == 2); + + REQUIRE_FALSE(l.load_asset("42:/21:/2")); + REQUIRE_FALSE(l.load_asset("42:/21:/none")); + REQUIRE_FALSE(l.load_asset("42:/21:/none:/2")); + } +} diff --git a/untests/sources/untests_high/library.cpp b/untests/sources/untests_high/library.cpp index 04385b08..48ae5e11 100644 --- a/untests/sources/untests_high/library.cpp +++ b/untests/sources/untests_high/library.cpp @@ -99,25 +99,33 @@ TEST_CASE("library"){ auto material_res = l.load_asset("material.json"); REQUIRE(material_res); - auto atlas_res = l.load_asset("atlas.json"); - REQUIRE(atlas_res); - REQUIRE(atlas_res->content().texture() == texture_res); - REQUIRE(atlas_res->content().regions().size() == 1); - REQUIRE(atlas_res->content().find_region("sprite")); - REQUIRE(atlas_res->content().find_region("sprite")->name == make_hash("sprite")); - REQUIRE(atlas_res->content().find_region("sprite")->pivot == v2f(1.f,2.f)); - REQUIRE(atlas_res->content().find_region("sprite")->texrect == b2f(5.f,6.f,7.f,8.f)); - REQUIRE_FALSE(atlas_res->content().find_region("sprite2")); - REQUIRE(atlas_res->content().shape_regions().size() == 1); - REQUIRE(atlas_res->content().find_shape_region("shape_sprite")); - REQUIRE(atlas_res->content().find_shape_region("shape_sprite")->name == make_hash("shape_sprite")); - REQUIRE(atlas_res->content().find_shape_region("shape_sprite")->pivot == v2f(3.f,4.f)); - REQUIRE(atlas_res->content().find_shape_region("shape_sprite")->points == vector{ - {1.f, 2.f}, - {3.f, 4.f}, - {5.f, 6.f} - }); - REQUIRE_FALSE(atlas_res->content().find_shape_region("shape_sprite2")); + { + auto atlas_res = l.load_asset("atlas.json"); + REQUIRE(atlas_res); + + REQUIRE(atlas_res->content().texture() == texture_res); + REQUIRE(atlas_res->content().regions().size() == 1); + REQUIRE(atlas_res->content().shape_regions().size() == 1); + + const atlas::region* region = atlas_res->content().find_region("sprite"); + REQUIRE(region); + REQUIRE(region->name == make_hash("sprite")); + REQUIRE(region->pivot == v2f(1.f,2.f)); + REQUIRE(region->texrect == b2f(5.f,6.f,7.f,8.f)); + + const atlas::shape_region* shape_region = atlas_res->content().find_shape_region("shape_sprite"); + REQUIRE(shape_region); + REQUIRE(shape_region->name == make_hash("shape_sprite")); + REQUIRE(shape_region->pivot == v2f(3.f,4.f)); + REQUIRE(shape_region->points == vector{ + {1.f, 2.f}, + {3.f, 4.f}, + {5.f, 6.f} + }); + + REQUIRE_FALSE(atlas_res->content().find_region("sprite2")); + REQUIRE_FALSE(atlas_res->content().find_shape_region("shape_sprite2")); + } { auto sprite_res = l.load_asset("sprite_a.json"); diff --git a/untests/sources/untests_high/starter.cpp b/untests/sources/untests_high/starter.cpp index 9becbba7..5143dbdb 100644 --- a/untests/sources/untests_high/starter.cpp +++ b/untests/sources/untests_high/starter.cpp @@ -4,8 +4,6 @@ * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ -#include - #include "_high.hpp" using namespace e2d;