separate asset and library headers

This commit is contained in:
2019-04-01 21:22:36 +07:00
parent 6a1b681ec8
commit 5fa2963c0c
12 changed files with 372 additions and 272 deletions

View File

@@ -30,6 +30,8 @@
#include "systems/render_system.hpp"
#include "address.hpp"
#include "asset.hpp"
#include "asset.inl"
#include "atlas.hpp"
#include "library.hpp"
#include "library.inl"

View File

@@ -45,12 +45,12 @@ namespace e2d
class content_asset;
class asset;
class library;
template < typename T >
class asset_cache;
class asset_cache_base;
class library;
class atlas;
class model;
class node;

View File

@@ -0,0 +1,115 @@
/*******************************************************************************
* 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";
}
};
//
// asset
//
class asset
: private noncopyable
, public ref_counter<asset> {
public:
asset();
virtual ~asset() noexcept;
};
using asset_ptr = intrusive_ptr<asset>;
using nested_content = hash_map<str_hash, asset_ptr>;
//
// 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<Asset>;
using load_result = intrusive_ptr<Asset>;
using load_async_result = stdex::promise<load_result>;
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<T> find_nested_asset(str_view name) const noexcept;
asset_ptr find_nested_asset(str_view name) const noexcept;
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<asset_cache_base*> caches_;
};
//
// asset_cache
//
template < typename Asset >
class asset_cache : public asset_cache_base
, public module<asset_cache<Asset>> {
public:
using asset_ptr = typename Asset::ptr;
public:
asset_cache(library& l);
~asset_cache() noexcept final;
asset_ptr find(str_hash address) const;
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<str_hash, asset_ptr> assets_;
};
}
#include "asset.inl"
#endif

View File

@@ -0,0 +1,126 @@
/*******************************************************************************
* 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<Asset, Content>::load_result
content_asset<Asset, Content>::create() {
return load_result(new Asset());
}
template < typename Asset, typename Content >
typename content_asset<Asset, Content>::load_result
content_asset<Asset, Content>::create(Content content) {
auto result = create();
result->fill(std::move(content));
return result;
}
template < typename Asset, typename Content >
typename content_asset<Asset, Content>::load_result
content_asset<Asset, Content>::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<Asset, Content>::fill(Content content) {
content_ = std::move(content);
}
template < typename Asset, typename Content >
void content_asset<Asset, Content>::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<Asset, Content>::content() const noexcept {
return content_;
}
template < typename Asset, typename Content >
template < typename T >
intrusive_ptr<T> content_asset<Asset, Content>::find_nested_asset(str_view name) const noexcept {
return dynamic_pointer_cast<T>(find_nested_asset(name));
}
template < typename Asset, typename Content >
asset_ptr content_asset<Asset, Content>::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<T>::asset_cache(library& l)
: library_(l) {}
template < typename T >
asset_cache<T>::~asset_cache() noexcept = default;
template < typename T >
typename asset_cache<T>::asset_ptr asset_cache<T>::find(str_hash address) const {
std::lock_guard<std::mutex> guard(mutex_);
const auto iter = assets_.find(address);
return iter != assets_.end()
? iter->second
: nullptr;
}
template < typename T >
void asset_cache<T>::store(str_hash address, const asset_ptr& asset) {
std::lock_guard<std::mutex> guard(mutex_);
assets_[address] = asset;
}
template < typename T >
void asset_cache<T>::clear() noexcept {
std::lock_guard<std::mutex> guard(mutex_);
assets_.clear();
}
template < typename T >
std::size_t asset_cache<T>::asset_count() const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return assets_.size();
}
template < typename T >
std::size_t asset_cache<T>::unload_self_unused_assets() noexcept {
std::lock_guard<std::mutex> 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;
}
}
#endif

View File

@@ -10,6 +10,8 @@
#include "_high.hpp"
#include "asset.hpp"
namespace e2d
{
//
@@ -23,90 +25,6 @@ namespace e2d
}
};
//
// asset_loading_exception
//
class asset_loading_exception : public exception {
const char* what() const noexcept override {
return "asset loading exception";
}
};
//
// asset
//
class asset
: private noncopyable
, public ref_counter<asset> {
public:
asset() = default;
virtual ~asset() noexcept = default;
};
using asset_ptr = intrusive_ptr<asset>;
using nested_content = hash_map<str_hash, asset_ptr>;
//
// 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<Asset>;
using load_result = intrusive_ptr<Asset>;
using load_async_result = stdex::promise<load_result>;
public:
static load_result create() {
return load_result(new Asset());
}
static load_result create(Content content) {
auto result = create();
result->fill(std::move(content));
return result;
}
static load_result create(Content content, nested_content nested_content) {
auto result = create();
result->fill(std::move(content), std::move(nested_content));
return result;
}
void fill(Content content) {
content_ = std::move(content);
}
void fill(Content content, nested_content nested_content) {
content_ = std::move(content);
nested_content_ = std::move(nested_content);
}
const Content& content() const noexcept {
return content_;
}
asset_ptr find_nested_asset(str_view name) const noexcept {
const auto iter = nested_content_.find(name);
return iter != nested_content_.end()
? iter->second
: nullptr;
}
template < typename T >
intrusive_ptr<T> find_nested_asset(str_view name) const noexcept {
return dynamic_pointer_cast<T>(find_nested_asset(name));
}
private:
Content content_;
nested_content nested_content_;
};
//
// library
//
@@ -127,48 +45,6 @@ namespace e2d
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<asset_cache_base*> caches_;
};
//
// asset_cache
//
template < typename Asset >
class asset_cache : public asset_cache_base
, public module<asset_cache<Asset>> {
public:
using asset_ptr = typename Asset::ptr;
public:
asset_cache(library& l);
~asset_cache() noexcept final;
asset_ptr find(str_hash address) const;
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<str_hash, asset_ptr> assets_;
};
}
#include "library.inl"

View File

@@ -13,9 +13,6 @@
namespace e2d
{
//
// library
//
template < typename Asset >
typename Asset::load_result library::load_asset(str_view address) const {
@@ -48,59 +45,6 @@ namespace e2d
return new_asset;
});
}
//
// asset_cache
//
template < typename T >
asset_cache<T>::asset_cache(library& l)
: library_(l) {}
template < typename T >
asset_cache<T>::~asset_cache() noexcept = default;
template < typename T >
typename asset_cache<T>::asset_ptr asset_cache<T>::find(str_hash address) const {
std::lock_guard<std::mutex> guard(mutex_);
const auto iter = assets_.find(address);
return iter != assets_.end()
? iter->second
: nullptr;
}
template < typename T >
void asset_cache<T>::store(str_hash address, const asset_ptr& asset) {
std::lock_guard<std::mutex> guard(mutex_);
assets_[address] = asset;
}
template < typename T >
void asset_cache<T>::clear() noexcept {
std::lock_guard<std::mutex> guard(mutex_);
assets_.clear();
}
template < typename T >
std::size_t asset_cache<T>::asset_count() const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return assets_.size();
}
template < typename T >
std::size_t asset_cache<T>::unload_self_unused_assets() noexcept {
std::lock_guard<std::mutex> 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;
}
}
#endif

View File

@@ -42,7 +42,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_;

View File

@@ -0,0 +1,42 @@
/*******************************************************************************
* 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 <enduro2d/high/asset.hpp>
namespace e2d
{
//
// asset
//
asset::asset() = default;
asset::~asset() noexcept = default;
//
// asset_cache_base
//
std::mutex asset_cache_base::mutex_;
hash_set<asset_cache_base*> asset_cache_base::caches_;
asset_cache_base::asset_cache_base() {
std::lock_guard<std::mutex> guard(mutex_);
caches_.insert(this);
}
asset_cache_base::~asset_cache_base() noexcept {
std::lock_guard<std::mutex> guard(mutex_);
caches_.erase(this);
}
std::size_t asset_cache_base::unload_all_unused_assets() noexcept {
std::lock_guard<std::mutex> 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();
});
}
}

View File

@@ -6,17 +6,8 @@
#include <enduro2d/high/library.hpp>
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*> asset_cache_base::caches_;
asset_cache_base::asset_cache_base() {
std::lock_guard<std::mutex> guard(mutex_);
caches_.insert(this);
}
asset_cache_base::~asset_cache_base() noexcept {
std::lock_guard<std::mutex> guard(mutex_);
caches_.erase(this);
}
std::size_t asset_cache_base::unload_all_unused_assets() noexcept {
std::lock_guard<std::mutex> 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();
});
}
}

View File

@@ -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_;

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
* 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<starter>(0, nullptr,
starter::parameters(
engine::parameters("asset_untests", "enduro2d")
.without_graphics(true)));
}
~safe_starter_initializer() noexcept {
modules::shutdown<starter>();
}
};
class fake_asset final : public content_asset<fake_asset, int> {
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_asset::create(21)},
{"84", fake_asset::create(84)}}))
: stdex::make_rejected_promise<load_result>(asset_loading_exception());
}
};
}
TEST_CASE("asset"){
safe_starter_initializer initializer;
library& l = the<library>();
{
REQUIRE_FALSE(l.load_asset<fake_asset>("none"));
auto fa = l.load_asset<fake_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<binary_asset>("21"));
REQUIRE(fa->find_nested_asset<fake_asset>("21"));
REQUIRE(fa->find_nested_asset<fake_asset>("21")->content() == 21);
REQUIRE(fa->find_nested_asset<fake_asset>("84")->content() == 84);
}
}

View File

@@ -22,37 +22,6 @@ namespace
modules::shutdown<starter>();
}
};
class fake_asset final : public content_asset<fake_asset, int> {
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_asset::create(21)},
{"84", fake_asset::create(84)}}))
: stdex::make_rejected_promise<load_result>(asset_loading_exception());
}
};
}
TEST_CASE("asset"){
safe_starter_initializer initializer;
library& l = the<library>();
{
REQUIRE_FALSE(l.load_asset<fake_asset>("none"));
auto fa = l.load_asset<fake_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<binary_asset>("21"));
REQUIRE(fa->find_nested_asset<fake_asset>("21"));
REQUIRE(fa->find_nested_asset<fake_asset>("21")->content() == 21);
REQUIRE(fa->find_nested_asset<fake_asset>("84")->content() == 84);
}
}
TEST_CASE("library"){
@@ -130,25 +99,33 @@ TEST_CASE("library"){
auto material_res = l.load_asset<material_asset>("material.json");
REQUIRE(material_res);
{
auto atlas_res = l.load_asset<atlas_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<v2f>{
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<v2f>{
{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_asset>("sprite_a.json");