basic content assets

This commit is contained in:
2018-11-27 23:50:38 +07:00
parent 827c667b88
commit ce8cea357d
11 changed files with 341 additions and 9 deletions
+1
View File
@@ -1 +1,2 @@
*.zip filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
+2
View File
@@ -8,4 +8,6 @@
#include "_high.hpp"
#include "assets.hpp"
#include "library.hpp"
#include "library.inl"
+7 -1
View File
@@ -6,9 +6,15 @@
#pragma once
#include "../core/_core.hpp"
#include "../core/_all.hpp"
namespace e2d
{
class asset;
class library;
class text_asset;
class binary_asset;
template < typename T >
class asset_cache;
}
+38
View File
@@ -0,0 +1,38 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#pragma once
#include "_high.hpp"
#include "library.hpp"
namespace e2d
{
template < typename T >
class content_asset : public asset {
public:
content_asset(T content)
: content_(std::move(content)) {}
const T& content() const noexcept {
return content_;
}
private:
T content_;
};
class text_asset final : public content_asset<str> {
public:
using content_asset<str>::content_asset;
static std::shared_ptr<text_asset> load(library& library, const url& url);
};
class binary_asset final : public content_asset<buffer> {
public:
using content_asset<buffer>::content_asset;
static std::shared_ptr<binary_asset> load(library& library, const url& url);
};
}
+51 -3
View File
@@ -4,12 +4,18 @@
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#ifndef E2D_INCLUDE_GUARD_C3A242D805B8481AB9F778BA8F272D72
#define E2D_INCLUDE_GUARD_C3A242D805B8481AB9F778BA8F272D72
#pragma once
#include "_high.hpp"
namespace e2d
{
//
// bad_library_operation
//
class bad_library_operation final : public exception {
public:
const char* what() const noexcept final {
@@ -17,12 +23,54 @@ namespace e2d
}
};
//
// asset
//
class asset : private noncopyable {
public:
asset();
virtual ~asset() noexcept;
};
using asset_ptr = std::shared_ptr<asset>;
//
// library
//
class library final : public module<library> {
public:
library();
library(const url& root);
~library() noexcept final;
template < typename T >
std::shared_ptr<T> load_asset(str_view address);
private:
class internal_state;
std::unique_ptr<internal_state> state_;
url root_;
};
//
// asset_cache
//
template < typename T >
class asset_cache : public module<asset_cache<T>> {
public:
asset_cache(library& l);
~asset_cache() noexcept final;
std::shared_ptr<T> find(str_hash address) const;
void store(str_hash address, const std::shared_ptr<T>& asset);
void clear();
void unload_unused_assets();
std::size_t asset_count() const noexcept;
private:
library& library_;
mutable std::mutex mutex_;
hash_map<str_hash, std::shared_ptr<T>> assets_;
};
}
#include "library.inl"
#endif
+95
View File
@@ -0,0 +1,95 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#ifndef E2D_INCLUDE_GUARD_C9B4A08B2E2A4A659AB390BDC6EBEFE8
#define E2D_INCLUDE_GUARD_C9B4A08B2E2A4A659AB390BDC6EBEFE8
#pragma once
#include "_high.hpp"
#include "library.hpp"
namespace e2d
{
//
// library
//
template < typename T >
std::shared_ptr<T> library::load_asset(str_view address) {
const auto asset_url = root_ / address;
if ( !modules::is_initialized<asset_cache<T>>() ) {
return T::load(*this, asset_url);
}
auto& cache = the<asset_cache<T>>();
const auto cached_asset = cache.find(address);
if ( cached_asset ) {
return cached_asset;
}
const auto new_asset = T::load(*this, asset_url);
if ( new_asset ) {
cache.store(address, new_asset);
return new_asset;
}
return 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 >
std::shared_ptr<T> 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 std::shared_ptr<T>& asset) {
std::lock_guard<std::mutex> guard(mutex_);
assets_[address] = asset;
}
template < typename T >
void asset_cache<T>::clear() {
std::lock_guard<std::mutex> guard(mutex_);
assets_.clear();
}
template < typename T >
void asset_cache<T>::unload_unused_assets() {
std::lock_guard<std::mutex> guard(mutex_);
for ( auto iter = assets_.begin(); iter != assets_.end(); ) {
if ( iter->second.unique() ) {
iter = assets_.erase(iter);
} else {
++iter;
}
}
}
template < typename T >
std::size_t asset_cache<T>::asset_count() const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return assets_.size();
}
}
#endif
+67
View File
@@ -0,0 +1,67 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#include <enduro2d/high/assets.hpp>
namespace
{
using namespace e2d;
}
namespace e2d
{
//
// text_asset
//
std::shared_ptr<text_asset> text_asset::load(library& library, const url& url) {
E2D_UNUSED(library);
input_stream_uptr stream = the<vfs>().open(url);
if ( !stream ) {
the<debug>().error("ASSETS: Failed to open text asset file:\n"
"--> Url: %0",
url);
return nullptr;
}
str content;
if ( !streams::try_read_tail(content, stream) ) {
the<debug>().error("ASSETS: Failed to read text asset file:\n"
"--> Url: %0",
url);
return nullptr;
}
return std::make_shared<text_asset>(std::move(content));
}
//
// binary_asset
//
std::shared_ptr<binary_asset> binary_asset::load(library& library, const url& url) {
E2D_UNUSED(library);
input_stream_uptr stream = the<vfs>().open(url);
if ( !stream ) {
the<debug>().error("ASSETS: Failed to open binary asset file:\n"
"--> Url: %0",
url);
return nullptr;
}
buffer content;
if ( !streams::try_read_tail(content, stream) ) {
the<debug>().error("ASSETS: Failed to read binary asset file:\n"
"--> Url: %0",
url);
return nullptr;
}
return std::make_shared<binary_asset>(std::move(content));
}
}
+11 -5
View File
@@ -6,20 +6,26 @@
#include <enduro2d/high/library.hpp>
namespace
{
using namespace e2d;
}
namespace e2d
{
//
// library::internal_state
// asset
//
class library::internal_state final : private e2d::noncopyable {
};
asset::asset() = default;
asset::~asset() noexcept = default;
//
// library
//
library::library()
: state_(new internal_state()){}
library::library(const url& root)
: root_(root) {}
library::~library() noexcept = default;
}
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7
size 5
+1
View File
@@ -0,0 +1 @@
hello
+65
View File
@@ -8,4 +8,69 @@
using namespace e2d;
TEST_CASE("library"){
modules::initialize<vfs>();
modules::initialize<debug>();
modules::initialize<window>(v2u{640, 480}, "Enduro2D", false);
modules::initialize<render>(the<debug>(), the<window>());
modules::initialize<library>(url{"resources://bin/library"});
modules::initialize<asset_cache<text_asset>>(the<library>());
modules::initialize<asset_cache<binary_asset>>(the<library>());
{
the<debug>().register_sink<debug_console_sink>();
the<vfs>().register_scheme<filesystem_file_source>("file");
}
{
str resources;
REQUIRE(filesystem::extract_predef_path(
resources,
filesystem::predef_path::resources));
REQUIRE(the<vfs>().register_scheme_alias(
"resources",
{"file", resources}));
}
{
library& l = the<library>();
auto text_res = l.load_asset<text_asset>("text_asset.txt");
REQUIRE(text_res);
REQUIRE(text_res->content() == "hello");
auto binary_res = l.load_asset<binary_asset>("binary_asset.bin");
REQUIRE(binary_res);
REQUIRE(binary_res->content() == buffer("world", 5));
auto empty_res = l.load_asset<binary_asset>("empty_asset");
REQUIRE_FALSE(empty_res);
auto binary_res_from_cache = l.load_asset<binary_asset>("binary_asset.bin");
REQUIRE(binary_res == binary_res_from_cache);
REQUIRE(the<asset_cache<text_asset>>().asset_count() == 1);
REQUIRE(the<asset_cache<binary_asset>>().asset_count() == 1);
the<asset_cache<text_asset>>().unload_unused_assets();
the<asset_cache<binary_asset>>().unload_unused_assets();
REQUIRE(the<asset_cache<text_asset>>().asset_count() == 1);
REQUIRE(the<asset_cache<binary_asset>>().asset_count() == 1);
text_res.reset();
the<asset_cache<text_asset>>().unload_unused_assets();
REQUIRE(the<asset_cache<text_asset>>().asset_count() == 0);
REQUIRE(the<asset_cache<binary_asset>>().asset_count() == 1);
binary_res.reset();
the<asset_cache<binary_asset>>().unload_unused_assets();
REQUIRE(the<asset_cache<binary_asset>>().asset_count() == 1);
binary_res_from_cache.reset();
the<asset_cache<binary_asset>>().unload_unused_assets();
REQUIRE(the<asset_cache<binary_asset>>().asset_count() == 0);
}
modules::shutdown<asset_cache<binary_asset>>();
modules::shutdown<asset_cache<text_asset>>();
modules::shutdown<library>();
modules::shutdown<render>();
modules::shutdown<window>();
modules::shutdown<debug>();
modules::shutdown<vfs>();
}