mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-16 14:08:59 +07:00
library: first impl of load_async
This commit is contained in:
@@ -60,7 +60,7 @@ if(E2D_BUILD_WITH_SANITIZER AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
|||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
||||||
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} ${E2D_SANITIZER_FLAGS}")
|
||||||
endif(E2D_BUILD_WITH_SANITIZER)
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# e2d sources
|
# e2d sources
|
||||||
|
|||||||
@@ -11,58 +11,67 @@
|
|||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
template < typename T >
|
class asset_loading_exception : public exception {
|
||||||
|
const char* what() const noexcept override = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename Asset, typename Content >
|
||||||
class content_asset : public asset {
|
class content_asset : public asset {
|
||||||
public:
|
public:
|
||||||
content_asset(T content)
|
using ptr = std::shared_ptr<Asset>;
|
||||||
|
|
||||||
|
using load_result = std::shared_ptr<Asset>;
|
||||||
|
using load_async_result = stdex::promise<load_result>;
|
||||||
|
public:
|
||||||
|
content_asset(Content content)
|
||||||
: content_(std::move(content)) {}
|
: content_(std::move(content)) {}
|
||||||
|
|
||||||
const T& content() const noexcept {
|
const Content& content() const noexcept {
|
||||||
return content_;
|
return content_;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
T content_;
|
Content content_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class text_asset final : public content_asset<str> {
|
class text_asset final : public content_asset<text_asset, str> {
|
||||||
public:
|
public:
|
||||||
using content_asset<str>::content_asset;
|
using content_asset<text_asset, str>::content_asset;
|
||||||
static std::shared_ptr<text_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class mesh_asset final : public content_asset<mesh> {
|
class mesh_asset final : public content_asset<mesh_asset, mesh> {
|
||||||
public:
|
public:
|
||||||
using content_asset<mesh>::content_asset;
|
using content_asset<mesh_asset, mesh>::content_asset;
|
||||||
static std::shared_ptr<mesh_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class image_asset final : public content_asset<image> {
|
class image_asset final : public content_asset<image_asset, image> {
|
||||||
public:
|
public:
|
||||||
using content_asset<image>::content_asset;
|
using content_asset<image_asset, image>::content_asset;
|
||||||
static std::shared_ptr<image_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class binary_asset final : public content_asset<buffer> {
|
class binary_asset final : public content_asset<binary_asset, buffer> {
|
||||||
public:
|
public:
|
||||||
using content_asset<buffer>::content_asset;
|
using content_asset<binary_asset, buffer>::content_asset;
|
||||||
static std::shared_ptr<binary_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class shader_asset final : public content_asset<shader_ptr> {
|
class shader_asset final : public content_asset<shader_asset, shader_ptr> {
|
||||||
public:
|
public:
|
||||||
using content_asset<shader_ptr>::content_asset;
|
using content_asset<shader_asset, shader_ptr>::content_asset;
|
||||||
static std::shared_ptr<shader_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class texture_asset final : public content_asset<texture_ptr> {
|
class texture_asset final : public content_asset<texture_asset, texture_ptr> {
|
||||||
public:
|
public:
|
||||||
using content_asset<texture_ptr>::content_asset;
|
using content_asset<texture_asset, texture_ptr>::content_asset;
|
||||||
static std::shared_ptr<texture_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
|
|
||||||
class material_asset final : public content_asset<render::material> {
|
class material_asset final : public content_asset<material_asset, render::material> {
|
||||||
public:
|
public:
|
||||||
using content_asset<render::material>::content_asset;
|
using content_asset<material_asset, render::material>::content_asset;
|
||||||
static std::shared_ptr<material_asset> load(library& library, str_view address);
|
static load_async_result load_async(library& library, str_view address);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,13 @@ namespace e2d
|
|||||||
library(const url& root);
|
library(const url& root);
|
||||||
~library() noexcept final;
|
~library() noexcept final;
|
||||||
|
|
||||||
|
const url& root() const noexcept;
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
std::shared_ptr<T> load_asset(str_view address);
|
std::shared_ptr<T> load_asset(str_view address);
|
||||||
const url& root() const noexcept;
|
|
||||||
|
template < typename T >
|
||||||
|
stdex::promise<std::shared_ptr<T>> load_asset_async(str_view address);
|
||||||
private:
|
private:
|
||||||
url root_;
|
url root_;
|
||||||
};
|
};
|
||||||
@@ -63,8 +67,8 @@ namespace e2d
|
|||||||
std::shared_ptr<T> find(str_hash address) const;
|
std::shared_ptr<T> find(str_hash address) const;
|
||||||
void store(str_hash address, const std::shared_ptr<T>& asset);
|
void store(str_hash address, const std::shared_ptr<T>& asset);
|
||||||
|
|
||||||
void clear();
|
void clear() noexcept;
|
||||||
void unload_unused_assets();
|
void unload_unused_assets() noexcept;
|
||||||
std::size_t asset_count() const noexcept;
|
std::size_t asset_count() const noexcept;
|
||||||
private:
|
private:
|
||||||
library& library_;
|
library& library_;
|
||||||
|
|||||||
@@ -19,24 +19,41 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
std::shared_ptr<T> library::load_asset(str_view address) {
|
std::shared_ptr<T> library::load_asset(str_view address) {
|
||||||
|
auto p = load_asset_async<T>(address);
|
||||||
|
|
||||||
|
if ( modules::is_initialized<deferrer>() && the<deferrer>().is_in_main_thread() ) {
|
||||||
|
const auto zero_us = time::to_chrono(make_microseconds(0));
|
||||||
|
while ( p.wait_for(zero_us) == stdex::promise_wait_status::timeout ) {
|
||||||
|
if ( 0 == the<deferrer>().scheduler().process_one_task().second ) {
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.get_or_default(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
stdex::promise<std::shared_ptr<T>> library::load_asset_async(str_view address) {
|
||||||
if ( !modules::is_initialized<asset_cache<T>>() ) {
|
if ( !modules::is_initialized<asset_cache<T>>() ) {
|
||||||
return T::load(*this, address);
|
return T::load_async(*this, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& cache = the<asset_cache<T>>();
|
auto& cache = the<asset_cache<T>>();
|
||||||
|
|
||||||
const auto cached_asset = cache.find(address);
|
auto cached_asset = cache.find(address);
|
||||||
if ( cached_asset ) {
|
if ( cached_asset ) {
|
||||||
return cached_asset;
|
return stdex::make_resolved_promise(std::move(cached_asset));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto new_asset = T::load(*this, address);
|
return T::load_async(*this, address)
|
||||||
if ( new_asset ) {
|
.then([
|
||||||
cache.store(address, new_asset);
|
&cache,
|
||||||
return new_asset;
|
address_hash = make_hash(address)
|
||||||
}
|
](const std::shared_ptr<T>& new_asset){
|
||||||
|
cache.store(address_hash, new_asset);
|
||||||
return nullptr;
|
return new_asset;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -66,16 +83,16 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
void asset_cache<T>::clear() {
|
void asset_cache<T>::clear() noexcept {
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
assets_.clear();
|
assets_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
void asset_cache<T>::unload_unused_assets() {
|
void asset_cache<T>::unload_unused_assets() noexcept {
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
for ( auto iter = assets_.begin(); iter != assets_.end(); ) {
|
for ( auto iter = assets_.begin(); iter != assets_.end(); ) {
|
||||||
if ( iter->second.unique() ) {
|
if ( 1 == iter->second.use_count() ) {
|
||||||
iter = assets_.erase(iter);
|
iter = assets_.erase(iter);
|
||||||
} else {
|
} else {
|
||||||
++iter;
|
++iter;
|
||||||
|
|||||||
29
sources/enduro2d/high/assets/assets.hpp
Normal file
29
sources/enduro2d/high/assets/assets.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 <enduro2d/high/assets.hpp>
|
||||||
|
|
||||||
|
#include <3rdparty/pugixml/pugixml.hpp>
|
||||||
|
|
||||||
|
#include <3rdparty/rapidjson/schema.h>
|
||||||
|
#include <3rdparty/rapidjson/document.h>
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
class xml_asset final : public content_asset<xml_asset, pugi::xml_document> {
|
||||||
|
public:
|
||||||
|
using content_asset<xml_asset, pugi::xml_document>::content_asset;
|
||||||
|
static load_async_result load_async(library& library, str_view address);
|
||||||
|
};
|
||||||
|
|
||||||
|
class json_asset final : public content_asset<json_asset, rapidjson::Document> {
|
||||||
|
public:
|
||||||
|
using content_asset<json_asset, rapidjson::Document>::content_asset;
|
||||||
|
static load_async_result load_async(library& library, str_view address);
|
||||||
|
};
|
||||||
|
}
|
||||||
39
sources/enduro2d/high/assets/binary_asset.cpp
Normal file
39
sources/enduro2d/high/assets/binary_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class binary_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "binary asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
binary_asset::load_async_result binary_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
E2D_UNUSED(library);
|
||||||
|
|
||||||
|
if ( !modules::is_initialized<vfs>() ) {
|
||||||
|
return stdex::make_rejected_promise<load_result>(
|
||||||
|
binary_asset_loading_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto asset_url = library.root() / address;
|
||||||
|
return the<vfs>().load_async(asset_url)
|
||||||
|
.then([](auto&& content){
|
||||||
|
return std::make_shared<binary_asset>(
|
||||||
|
std::forward<decltype(content)>(content));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
39
sources/enduro2d/high/assets/image_asset.cpp
Normal file
39
sources/enduro2d/high/assets/image_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class image_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "image asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
image_asset::load_async_result image_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<binary_asset>(address)
|
||||||
|
.then([](const binary_asset::ptr& image_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw image_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([image_data](){
|
||||||
|
image content;
|
||||||
|
if ( !images::try_load_image(content, image_data->content()) ) {
|
||||||
|
throw image_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<image_asset>(std::move(content));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
39
sources/enduro2d/high/assets/json_asset.cpp
Normal file
39
sources/enduro2d/high/assets/json_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class json_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "json asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
json_asset::load_async_result json_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<text_asset>(address)
|
||||||
|
.then([](const text_asset::ptr& json_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw json_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([json_data](){
|
||||||
|
rapidjson::Document doc;
|
||||||
|
if ( doc.Parse(json_data->content().c_str()).HasParseError() ) {
|
||||||
|
throw json_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<json_asset>(std::move(doc));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,40 +4,20 @@
|
|||||||
* Copyright (C) 2018 Matvey Cherevko
|
* Copyright (C) 2018 Matvey Cherevko
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <enduro2d/high/assets.hpp>
|
#include "assets.hpp"
|
||||||
|
|
||||||
#include <3rdparty/rapidjson/schema.h>
|
|
||||||
#include <3rdparty/rapidjson/document.h>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace e2d;
|
using namespace e2d;
|
||||||
|
|
||||||
template < typename T >
|
class material_asset_loading_exception final : public asset_loading_exception {
|
||||||
const char* asset_schema_source() noexcept;
|
const char* what() const noexcept final {
|
||||||
|
return "material asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
const char* material_asset_schema_source = R"json(
|
||||||
const char* asset_schema_source<shader_asset>() noexcept {
|
{
|
||||||
return R"json({
|
|
||||||
"type" : "object",
|
|
||||||
"required" : [ "vertex", "fragment" ],
|
|
||||||
"additionalProperties" : false,
|
|
||||||
"properties" : {
|
|
||||||
"vertex" : { "$ref": "#/definitions/generic_address" },
|
|
||||||
"fragment" : { "$ref": "#/definitions/generic_address" }
|
|
||||||
},
|
|
||||||
"definitions" : {
|
|
||||||
"generic_address" : {
|
|
||||||
"type" : "string",
|
|
||||||
"minLength" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})json";
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const char* asset_schema_source<material_asset>() noexcept {
|
|
||||||
return R"json({
|
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"properties" : {
|
"properties" : {
|
||||||
@@ -387,47 +367,24 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})json";
|
})json";
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
const rapidjson::SchemaDocument& material_asset_schema() {
|
||||||
const rapidjson::SchemaDocument& asset_file_schema() {
|
static std::mutex mutex;
|
||||||
static std::unique_ptr<rapidjson::SchemaDocument> schema;
|
static std::unique_ptr<rapidjson::SchemaDocument> schema;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> guard(mutex);
|
||||||
if ( !schema ) {
|
if ( !schema ) {
|
||||||
rapidjson::Document doc;
|
rapidjson::Document doc;
|
||||||
if ( doc.Parse(asset_schema_source<T>()).HasParseError() ) {
|
if ( doc.Parse(material_asset_schema_source).HasParseError() ) {
|
||||||
the<debug>().error("ASSETS: Failed to parse asset file schema");
|
the<debug>().error("ASSETS: Failed to parse material asset schema");
|
||||||
throw bad_library_operation();
|
throw material_asset_loading_exception();
|
||||||
}
|
}
|
||||||
schema = std::make_unique<rapidjson::SchemaDocument>(doc);
|
schema = std::make_unique<rapidjson::SchemaDocument>(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *schema;
|
return *schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
bool load_json_asset_file(library& library, str_view address, rapidjson::Document& doc) {
|
|
||||||
const auto json_data = library.load_asset<text_asset>(address);
|
|
||||||
if ( !json_data ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( doc.Parse(json_data->content().c_str()).HasParseError() ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to parse json asset file:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rapidjson::SchemaValidator validator(asset_file_schema<T>());
|
|
||||||
if ( !doc.Accept(validator) ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to validate json asset file:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse_stencil_op(str_view str, render::stencil_op& op) noexcept {
|
bool parse_stencil_op(str_view str, render::stencil_op& op) noexcept {
|
||||||
#define DEFINE_IF(x) if ( str == #x ) { op = render::stencil_op::x; return true; }
|
#define DEFINE_IF(x) if ( str == #x ) { op = render::stencil_op::x; return true; }
|
||||||
DEFINE_IF(keep);
|
DEFINE_IF(keep);
|
||||||
@@ -741,222 +698,266 @@ namespace
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_property_block_samplers(
|
stdex::promise<shader_ptr> parse_shader_block(
|
||||||
library& library,
|
library& library,
|
||||||
str_view address,
|
str_view parent_address,
|
||||||
const rapidjson::Value& root,
|
const rapidjson::Value& root)
|
||||||
render::property_block& props)
|
|
||||||
{
|
{
|
||||||
const auto parent_address = path::parent_path(address);
|
E2D_ASSERT(root.IsString());
|
||||||
|
const auto shader_address =
|
||||||
|
path::combine(parent_address, root.GetString());
|
||||||
|
return library.load_asset_async<shader_asset>(shader_address)
|
||||||
|
.then([](const shader_asset::ptr& shader){
|
||||||
|
return shader->content();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ( root.HasMember("samplers") ) {
|
stdex::promise<texture_ptr> parse_texture_block(
|
||||||
E2D_ASSERT(root["samplers"].IsArray());
|
library& library,
|
||||||
const auto& samplers_json = root["samplers"];
|
str_view parent_address,
|
||||||
|
const rapidjson::Value& root)
|
||||||
|
{
|
||||||
|
E2D_ASSERT(root.IsString());
|
||||||
|
const auto texture_address =
|
||||||
|
path::combine(parent_address, root.GetString());
|
||||||
|
return library.load_asset_async<texture_asset>(texture_address)
|
||||||
|
.then([](const texture_asset::ptr& texture){
|
||||||
|
return texture->content();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for ( rapidjson::SizeType i = 0; i < samplers_json.Size(); ++i ) {
|
stdex::promise<std::pair<str_hash,render::sampler_state>> parse_sampler_state(
|
||||||
E2D_ASSERT(samplers_json[i].IsObject());
|
library& library,
|
||||||
const auto& sampler_json = samplers_json[i];
|
str_view parent_address,
|
||||||
|
const rapidjson::Value& root)
|
||||||
|
{
|
||||||
|
render::sampler_state content;
|
||||||
|
|
||||||
E2D_ASSERT(sampler_json.HasMember("name") && sampler_json["name"].IsString());
|
E2D_ASSERT(root.HasMember("name") && root["name"].IsString());
|
||||||
E2D_ASSERT(sampler_json.HasMember("texture") && sampler_json["texture"].IsString());
|
E2D_ASSERT(root.HasMember("texture") && root["texture"].IsString());
|
||||||
|
|
||||||
const auto texture = library.load_asset<texture_asset>(
|
auto name_hash = make_hash(root["name"].GetString());
|
||||||
path::combine(parent_address, sampler_json["texture"].GetString()));
|
|
||||||
|
|
||||||
auto sampler = render::sampler_state()
|
auto texture_p = root.HasMember("texture")
|
||||||
.texture(texture ? texture->content() : texture_ptr());
|
? parse_texture_block(library, parent_address, root["texture"])
|
||||||
|
: stdex::make_resolved_promise<texture_ptr>(nullptr);
|
||||||
|
|
||||||
if ( sampler_json.HasMember("wrap") ) {
|
if ( root.HasMember("wrap") ) {
|
||||||
if ( sampler_json["wrap"].IsObject() ) {
|
const auto& wrap_json = root["wrap"];
|
||||||
const auto& sampler_wrap_json = sampler_json["wrap"];
|
if ( wrap_json.IsObject() ) {
|
||||||
|
if ( wrap_json.HasMember("s") ) {
|
||||||
if ( sampler_wrap_json.HasMember("s") ) {
|
E2D_ASSERT(wrap_json["s"].IsString());
|
||||||
E2D_ASSERT(sampler_wrap_json["s"].IsString());
|
auto wrap = content.s_wrap();
|
||||||
auto wrap = sampler.s_wrap();
|
if ( parse_sampler_wrap(wrap_json["s"].GetString(), wrap) ) {
|
||||||
if ( parse_sampler_wrap(sampler_wrap_json["s"].GetString(), wrap) ) {
|
content.s_wrap(wrap);
|
||||||
sampler.s_wrap(wrap);
|
} else {
|
||||||
} else {
|
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sampler_wrap_json.HasMember("t") ) {
|
|
||||||
E2D_ASSERT(sampler_wrap_json["t"].IsString());
|
|
||||||
auto wrap = sampler.t_wrap();
|
|
||||||
if ( parse_sampler_wrap(sampler_wrap_json["t"].GetString(), wrap) ) {
|
|
||||||
sampler.t_wrap(wrap);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sampler_wrap_json.HasMember("r") ) {
|
|
||||||
E2D_ASSERT(sampler_wrap_json["r"].IsString());
|
|
||||||
auto wrap = sampler.r_wrap();
|
|
||||||
if ( parse_sampler_wrap(sampler_wrap_json["r"].GetString(), wrap) ) {
|
|
||||||
sampler.r_wrap(wrap);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( sampler_json["wrap"].IsString() ) {
|
|
||||||
auto wrap = sampler.s_wrap();
|
|
||||||
if ( parse_sampler_wrap(sampler_json["wrap"].GetString(), wrap) ) {
|
|
||||||
sampler.wrap(wrap);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sampler_json.HasMember("filter") ) {
|
if ( wrap_json.HasMember("t") ) {
|
||||||
if ( sampler_json["filter"].IsObject() ) {
|
E2D_ASSERT(wrap_json["t"].IsString());
|
||||||
const auto& sampler_filter_json = sampler_json["filter"];
|
auto wrap = content.t_wrap();
|
||||||
|
if ( parse_sampler_wrap(wrap_json["t"].GetString(), wrap) ) {
|
||||||
if ( sampler_filter_json.HasMember("min") ) {
|
content.t_wrap(wrap);
|
||||||
E2D_ASSERT(sampler_filter_json["min"].IsString());
|
} else {
|
||||||
auto filter = sampler.min_filter();
|
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
||||||
if ( parse_sampler_min_filter(sampler_filter_json["min"].GetString(), filter) ) {
|
|
||||||
sampler.min_filter(filter);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler min filter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sampler_filter_json.HasMember("mag") ) {
|
|
||||||
E2D_ASSERT(sampler_filter_json["mag"].IsString());
|
|
||||||
auto filter = sampler.mag_filter();
|
|
||||||
if ( parse_sampler_mag_filter(sampler_filter_json["mag"].GetString(), filter) ) {
|
|
||||||
sampler.mag_filter(filter);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler mag filter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( sampler_json["filter"].IsString() ) {
|
|
||||||
auto min_filter = sampler.min_filter();
|
|
||||||
if ( parse_sampler_min_filter(sampler_json["filter"].GetString(), min_filter) ) {
|
|
||||||
sampler.min_filter(min_filter);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler filter");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mag_filter = sampler.mag_filter();
|
|
||||||
if ( parse_sampler_mag_filter(sampler_json["filter"].GetString(), mag_filter) ) {
|
|
||||||
sampler.mag_filter(mag_filter);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected sampler filter");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
props.sampler(
|
if ( wrap_json.HasMember("r") ) {
|
||||||
sampler_json["name"].GetString(),
|
E2D_ASSERT(wrap_json["r"].IsString());
|
||||||
sampler);
|
auto wrap = content.r_wrap();
|
||||||
|
if ( parse_sampler_wrap(wrap_json["r"].GetString(), wrap) ) {
|
||||||
|
content.r_wrap(wrap);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ( wrap_json.IsString() ) {
|
||||||
|
auto wrap = content.s_wrap();
|
||||||
|
if ( parse_sampler_wrap(wrap_json.GetString(), wrap) ) {
|
||||||
|
content.wrap(wrap);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler wrap");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
if ( root.HasMember("filter") ) {
|
||||||
|
const auto& filter_json = root["filter"];
|
||||||
|
if ( filter_json.IsObject() ) {
|
||||||
|
if ( filter_json.HasMember("min") ) {
|
||||||
|
E2D_ASSERT(filter_json["min"].IsString());
|
||||||
|
auto filter = content.min_filter();
|
||||||
|
if ( parse_sampler_min_filter(filter_json["min"].GetString(), filter) ) {
|
||||||
|
content.min_filter(filter);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler min filter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( filter_json.HasMember("mag") ) {
|
||||||
|
E2D_ASSERT(filter_json["mag"].IsString());
|
||||||
|
auto filter = content.mag_filter();
|
||||||
|
if ( parse_sampler_mag_filter(filter_json["mag"].GetString(), filter) ) {
|
||||||
|
content.mag_filter(filter);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler mag filter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ( filter_json.IsString() ) {
|
||||||
|
auto min_filter = content.min_filter();
|
||||||
|
if ( parse_sampler_min_filter(filter_json.GetString(), min_filter) ) {
|
||||||
|
content.min_filter(min_filter);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mag_filter = content.mag_filter();
|
||||||
|
if ( parse_sampler_mag_filter(filter_json.GetString(), mag_filter) ) {
|
||||||
|
content.mag_filter(mag_filter);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected sampler filter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture_p
|
||||||
|
.then([name_hash, content](const texture_ptr& texture) mutable {
|
||||||
|
content.texture(texture);
|
||||||
|
return std::make_pair(name_hash, content);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_property_block_properties(
|
bool parse_property_block_properties(
|
||||||
const rapidjson::Value& root,
|
const rapidjson::Value& root,
|
||||||
render::property_block& props)
|
render::property_block& props)
|
||||||
{
|
{
|
||||||
if ( root.HasMember("properties") ) {
|
E2D_ASSERT(root.IsArray());
|
||||||
E2D_ASSERT(root["properties"].IsArray());
|
for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) {
|
||||||
const auto& root_properties = root["properties"];
|
E2D_ASSERT(root[i].IsObject());
|
||||||
|
const auto& property_json = root[i];
|
||||||
|
|
||||||
for ( rapidjson::SizeType i = 0; i < root_properties.Size(); ++i ) {
|
E2D_ASSERT(property_json.HasMember("name") && property_json["name"].IsString());
|
||||||
E2D_ASSERT(root_properties[i].IsObject());
|
E2D_ASSERT(property_json.HasMember("type") && property_json["type"].IsString());
|
||||||
const auto& property_json = root_properties[i];
|
|
||||||
|
|
||||||
E2D_ASSERT(property_json.HasMember("name") && property_json["name"].IsString());
|
if ( 0 == std::strcmp(property_json["type"].GetString(), "i32") ) {
|
||||||
E2D_ASSERT(property_json.HasMember("type") && property_json["type"].IsString());
|
i32 value = 0;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
if ( 0 == std::strcmp(property_json["type"].GetString(), "i32") ) {
|
E2D_ASSERT(property_json["value"].IsNumber());
|
||||||
i32 value = 0;
|
value = property_json["value"].GetInt();
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
E2D_ASSERT(property_json["value"].IsNumber());
|
|
||||||
value = property_json["value"].GetInt();
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "f32") ) {
|
|
||||||
f32 value = 0;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
E2D_ASSERT(property_json["value"].IsNumber());
|
|
||||||
value = property_json["value"].GetFloat();
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v2i") ) {
|
|
||||||
v2i value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v3i") ) {
|
|
||||||
v3i value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v4i") ) {
|
|
||||||
v4i value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v2f") ) {
|
|
||||||
v2f value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v3f") ) {
|
|
||||||
v3f value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v4f") ) {
|
|
||||||
v4f value;
|
|
||||||
if ( property_json.HasMember("value") ) {
|
|
||||||
if ( !parse_property_value(property_json["value"], value) ) {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props.property(property_json["name"].GetString(), value);
|
|
||||||
} else {
|
|
||||||
E2D_ASSERT_MSG(false, "unexpected property type");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "f32") ) {
|
||||||
|
f32 value = 0;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
E2D_ASSERT(property_json["value"].IsNumber());
|
||||||
|
value = property_json["value"].GetFloat();
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v2i") ) {
|
||||||
|
v2i value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v3i") ) {
|
||||||
|
v3i value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v4i") ) {
|
||||||
|
v4i value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v2f") ) {
|
||||||
|
v2f value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v3f") ) {
|
||||||
|
v3f value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else if ( 0 == std::strcmp(property_json["type"].GetString(), "v4f") ) {
|
||||||
|
v4f value;
|
||||||
|
if ( property_json.HasMember("value") ) {
|
||||||
|
if ( !parse_property_value(property_json["value"], value) ) {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.property(property_json["name"].GetString(), value);
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unexpected property type");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_property_block(
|
stdex::promise<render::property_block> parse_property_block(
|
||||||
library& library,
|
library& library,
|
||||||
str_view address,
|
str_view parent_address,
|
||||||
const rapidjson::Value& root,
|
const rapidjson::Value& root)
|
||||||
render::property_block& props)
|
|
||||||
{
|
{
|
||||||
return parse_property_block_samplers(library, address, root, props)
|
render::property_block content;
|
||||||
&& parse_property_block_properties(root, props);
|
|
||||||
|
vector<stdex::promise<std::pair<str_hash, render::sampler_state>>> samplers_p;
|
||||||
|
|
||||||
|
if ( root.HasMember("samplers") ) {
|
||||||
|
E2D_ASSERT(root["samplers"].IsArray());
|
||||||
|
const auto& samplers_json = root["samplers"];
|
||||||
|
|
||||||
|
samplers_p.reserve(samplers_json.Size());
|
||||||
|
for ( rapidjson::SizeType i = 0; i < samplers_json.Size(); ++i ) {
|
||||||
|
E2D_ASSERT(samplers_json[i].IsObject());
|
||||||
|
const auto& sampler_json = samplers_json[i];
|
||||||
|
samplers_p.emplace_back(
|
||||||
|
parse_sampler_state(library, parent_address, sampler_json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( root.HasMember("properties") ) {
|
||||||
|
E2D_ASSERT(root["properties"].IsArray());
|
||||||
|
const auto& properties_json = root["properties"];
|
||||||
|
if ( !parse_property_block_properties(properties_json, content) ) {
|
||||||
|
return stdex::make_rejected_promise<render::property_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdex::make_all_promise(samplers_p)
|
||||||
|
.then([content](auto&& results) mutable {
|
||||||
|
for ( auto& result : results ) {
|
||||||
|
content.sampler(
|
||||||
|
std::move(result.first),
|
||||||
|
std::move(result.second));
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_depth_state(
|
bool parse_depth_state(
|
||||||
@@ -1292,306 +1293,156 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_state_block(
|
stdex::promise<render::state_block> parse_state_block(
|
||||||
const rapidjson::Value& root,
|
const rapidjson::Value& root)
|
||||||
render::state_block& states)
|
|
||||||
{
|
{
|
||||||
|
render::state_block content;
|
||||||
|
|
||||||
if ( root.HasMember("depth_state") ) {
|
if ( root.HasMember("depth_state") ) {
|
||||||
E2D_ASSERT(root["depth_state"].IsObject());
|
E2D_ASSERT(root["depth_state"].IsObject());
|
||||||
if ( !parse_depth_state(root["depth_state"], states.depth()) ) {
|
if ( !parse_depth_state(root["depth_state"], content.depth()) ) {
|
||||||
return false;
|
return stdex::make_rejected_promise<render::state_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( root.HasMember("stencil_state") ) {
|
if ( root.HasMember("stencil_state") ) {
|
||||||
E2D_ASSERT(root["stencil_state"].IsObject());
|
E2D_ASSERT(root["stencil_state"].IsObject());
|
||||||
if ( !parse_stencil_state(root["stencil_state"], states.stencil()) ) {
|
if ( !parse_stencil_state(root["stencil_state"], content.stencil()) ) {
|
||||||
return false;
|
return stdex::make_rejected_promise<render::state_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( root.HasMember("culling_state") ) {
|
if ( root.HasMember("culling_state") ) {
|
||||||
E2D_ASSERT(root["culling_state"].IsObject());
|
E2D_ASSERT(root["culling_state"].IsObject());
|
||||||
if ( !parse_culling_state(root["culling_state"], states.culling()) ) {
|
if ( !parse_culling_state(root["culling_state"], content.culling()) ) {
|
||||||
return false;
|
return stdex::make_rejected_promise<render::state_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( root.HasMember("blending_state") ) {
|
if ( root.HasMember("blending_state") ) {
|
||||||
E2D_ASSERT(root["blending_state"].IsObject());
|
E2D_ASSERT(root["blending_state"].IsObject());
|
||||||
if ( !parse_blending_state(root["blending_state"], states.blending()) ) {
|
if ( !parse_blending_state(root["blending_state"], content.blending()) ) {
|
||||||
return false;
|
return stdex::make_rejected_promise<render::state_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( root.HasMember("capabilities_state") ) {
|
if ( root.HasMember("capabilities_state") ) {
|
||||||
E2D_ASSERT(root["capabilities_state"].IsObject());
|
E2D_ASSERT(root["capabilities_state"].IsObject());
|
||||||
if ( !parse_capabilities_state(root["capabilities_state"], states.capabilities()) ) {
|
if ( !parse_capabilities_state(root["capabilities_state"], content.capabilities()) ) {
|
||||||
return false;
|
return stdex::make_rejected_promise<render::state_block>(
|
||||||
|
material_asset_loading_exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return stdex::make_resolved_promise(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_pass_state(
|
stdex::promise<render::pass_state> parse_pass_state(
|
||||||
library& library,
|
library& library,
|
||||||
str_view address,
|
str_view parent_address,
|
||||||
const rapidjson::Value& root,
|
const rapidjson::Value& root)
|
||||||
render::pass_state& pass)
|
|
||||||
{
|
{
|
||||||
const auto parent_address = path::parent_path(address);
|
auto shader_p = root.HasMember("shader")
|
||||||
|
? parse_shader_block(library, parent_address, root["shader"])
|
||||||
|
: stdex::make_resolved_promise<shader_ptr>(nullptr);
|
||||||
|
|
||||||
if ( root.HasMember("shader") ) {
|
auto state_block_p = root.HasMember("state_block")
|
||||||
E2D_ASSERT(root["shader"].IsString());
|
? parse_state_block(root["state_block"])
|
||||||
|
: stdex::make_resolved_promise<render::state_block>(render::state_block());
|
||||||
|
|
||||||
const auto shader = library.load_asset<shader_asset>(
|
auto property_block_p = root.HasMember("property_block")
|
||||||
path::combine(parent_address, root["shader"].GetString()));
|
? parse_property_block(library, parent_address, root["property_block"])
|
||||||
|
: stdex::make_resolved_promise<render::property_block>(render::property_block());
|
||||||
|
|
||||||
pass.shader(shader ? shader->content() : shader_ptr());
|
return stdex::make_tuple_promise(std::make_tuple(
|
||||||
}
|
std::move(shader_p),
|
||||||
|
std::move(state_block_p),
|
||||||
|
std::move(property_block_p)
|
||||||
|
)).then([](const std::tuple<
|
||||||
|
shader_ptr,
|
||||||
|
render::state_block,
|
||||||
|
render::property_block
|
||||||
|
>& result) {
|
||||||
|
render::pass_state content;
|
||||||
|
content.shader(std::get<0>(result));
|
||||||
|
content.states(std::get<1>(result));
|
||||||
|
content.properties(std::get<2>(result));
|
||||||
|
return content;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ( root.HasMember("state_block") ) {
|
stdex::promise<render::material> parse_material(
|
||||||
E2D_ASSERT(root["state_block"].IsObject());
|
library& library,
|
||||||
const auto& state_block_json = root["state_block"];
|
str_view parent_address,
|
||||||
|
const rapidjson::Value& root)
|
||||||
|
{
|
||||||
|
vector<stdex::promise<render::pass_state>> passes_p;
|
||||||
|
|
||||||
render::state_block states;
|
if ( root.HasMember("passes") ) {
|
||||||
if ( !parse_state_block(state_block_json, states) ) {
|
E2D_ASSERT(root["passes"].IsArray());
|
||||||
return false;
|
const auto& passes_json = root["passes"];
|
||||||
|
|
||||||
|
passes_p.reserve(passes_json.Size());
|
||||||
|
for ( rapidjson::SizeType i = 0; i < passes_json.Size(); ++i ) {
|
||||||
|
E2D_ASSERT(passes_json[i].IsObject());
|
||||||
|
const auto& pass_json = passes_json[i];
|
||||||
|
passes_p.emplace_back(
|
||||||
|
parse_pass_state(library, parent_address, pass_json));
|
||||||
}
|
}
|
||||||
|
|
||||||
pass.states(states);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( root.HasMember("property_block") ) {
|
auto property_block_p = root.HasMember("property_block")
|
||||||
E2D_ASSERT(root["property_block"].IsObject());
|
? parse_property_block(library, parent_address, root["property_block"])
|
||||||
const auto& property_block_json = root["property_block"];
|
: stdex::make_resolved_promise(render::property_block());
|
||||||
|
|
||||||
render::property_block props;
|
return stdex::make_tuple_promise(std::make_tuple(
|
||||||
if ( !parse_property_block(library, address, property_block_json, props) ) {
|
stdex::make_all_promise(passes_p),
|
||||||
return false;
|
std::move(property_block_p)))
|
||||||
|
.then([](const std::tuple<
|
||||||
|
vector<render::pass_state>,
|
||||||
|
render::property_block
|
||||||
|
>& results) {
|
||||||
|
render::material content;
|
||||||
|
for ( auto& pass : std::get<0>(results) ) {
|
||||||
|
content.add_pass(pass);
|
||||||
}
|
}
|
||||||
|
content.properties(std::get<1>(results));
|
||||||
pass.properties(props);
|
return content;
|
||||||
}
|
});
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
//
|
material_asset::load_async_result material_asset::load_async(
|
||||||
// text_asset
|
library& library, str_view address)
|
||||||
//
|
{
|
||||||
|
return library.load_asset_async<json_asset>(address)
|
||||||
std::shared_ptr<text_asset> text_asset::load(library& library, str_view address) {
|
.then([
|
||||||
E2D_UNUSED(library);
|
&library,
|
||||||
|
parent_address = path::parent_path(address)
|
||||||
const auto asset_url = library.root() / address;
|
](const json_asset::ptr& material_data){
|
||||||
input_stream_uptr stream = modules::is_initialized<vfs>()
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
? the<vfs>().read(asset_url)
|
throw material_asset_loading_exception();
|
||||||
: input_stream_uptr();
|
|
||||||
|
|
||||||
if ( !stream ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to open text asset file:\n"
|
|
||||||
"--> Url: %0",
|
|
||||||
asset_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",
|
|
||||||
asset_url);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<text_asset>(std::move(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// mesh_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<mesh_asset> mesh_asset::load(library& library, str_view address) {
|
|
||||||
const auto mesh_data = library.load_asset<binary_asset>(address);
|
|
||||||
if ( !mesh_data ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh content;
|
|
||||||
if ( !meshes::try_load_mesh(content, mesh_data->content()) ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to create mesh asset:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<mesh_asset>(std::move(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// image_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<image_asset> image_asset::load(library& library, str_view address) {
|
|
||||||
const auto image_data = library.load_asset<binary_asset>(address);
|
|
||||||
if ( !image_data ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
image content;
|
|
||||||
if ( !images::try_load_image(content, image_data->content()) ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to create image asset:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<image_asset>(std::move(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// binary_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<binary_asset> binary_asset::load(library& library, str_view address) {
|
|
||||||
E2D_UNUSED(library);
|
|
||||||
|
|
||||||
const auto asset_url = library.root() / address;
|
|
||||||
input_stream_uptr stream = modules::is_initialized<vfs>()
|
|
||||||
? the<vfs>().read(asset_url)
|
|
||||||
: input_stream_uptr();
|
|
||||||
|
|
||||||
if ( !stream ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to open binary asset file:\n"
|
|
||||||
"--> Url: %0",
|
|
||||||
asset_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",
|
|
||||||
asset_url);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<binary_asset>(std::move(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// shader_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<shader_asset> shader_asset::load(library& library, str_view address) {
|
|
||||||
rapidjson::Document doc;
|
|
||||||
if ( !load_json_asset_file<shader_asset>(library, address, doc) ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto parent_address = path::parent_path(address);
|
|
||||||
|
|
||||||
E2D_ASSERT(doc.HasMember("vertex") && doc["vertex"].IsString());
|
|
||||||
const auto vertex_source_data = library.load_asset<text_asset>(
|
|
||||||
path::combine(parent_address, doc["vertex"].GetString()));
|
|
||||||
|
|
||||||
if ( !vertex_source_data ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
E2D_ASSERT(doc.HasMember("fragment") && doc["fragment"].IsString());
|
|
||||||
const auto fragment_source_data = library.load_asset<text_asset>(
|
|
||||||
path::combine(parent_address, doc["fragment"].GetString()));
|
|
||||||
|
|
||||||
if ( !fragment_source_data ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto content = modules::is_initialized<render>()
|
|
||||||
? the<render>().create_shader(
|
|
||||||
vertex_source_data->content(),
|
|
||||||
fragment_source_data->content())
|
|
||||||
: shader_ptr();
|
|
||||||
|
|
||||||
if ( !content ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to create shader asset:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<shader_asset>(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// texture_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<texture_asset> texture_asset::load(library& library, str_view address) {
|
|
||||||
const auto texture_data = library.load_asset<image_asset>(address);
|
|
||||||
if ( !texture_data ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto content = modules::is_initialized<render>()
|
|
||||||
? the<render>().create_texture(texture_data->content())
|
|
||||||
: texture_ptr();
|
|
||||||
|
|
||||||
if ( !content ) {
|
|
||||||
the<debug>().error("ASSETS: Failed to create texture asset:\n"
|
|
||||||
"--> Address: %0",
|
|
||||||
address);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<texture_asset>(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// material_asset
|
|
||||||
//
|
|
||||||
|
|
||||||
std::shared_ptr<material_asset> material_asset::load(library& library, str_view address) {
|
|
||||||
rapidjson::Document doc;
|
|
||||||
if ( !load_json_asset_file<material_asset>(library, address, doc) ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
render::material content;
|
|
||||||
|
|
||||||
if ( doc.HasMember("passes") ) {
|
|
||||||
E2D_ASSERT(doc["passes"].IsArray());
|
|
||||||
const auto& passes_json = doc["passes"];
|
|
||||||
|
|
||||||
for ( rapidjson::SizeType i = 0; i < passes_json.Size(); ++i ) {
|
|
||||||
E2D_ASSERT(passes_json[i].IsObject());
|
|
||||||
const auto& pass_json = passes_json[i];
|
|
||||||
|
|
||||||
render::pass_state pass;
|
|
||||||
if ( !parse_pass_state(library, address, pass_json, pass) ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([material_data](){
|
||||||
content.add_pass(pass);
|
const rapidjson::Document& doc = material_data->content();
|
||||||
}
|
rapidjson::SchemaValidator validator(material_asset_schema());
|
||||||
}
|
if ( !doc.Accept(validator) ) {
|
||||||
|
throw material_asset_loading_exception();
|
||||||
if ( doc.HasMember("property_block") ) {
|
}
|
||||||
E2D_ASSERT(doc["property_block"].IsObject());
|
})
|
||||||
const auto& property_block_json = doc["property_block"];
|
.then([&library, parent_address, material_data](){
|
||||||
|
return parse_material(
|
||||||
render::property_block props;
|
library, parent_address, material_data->content());
|
||||||
if ( !parse_property_block(library, address, property_block_json, props) ) {
|
})
|
||||||
return nullptr;
|
.then([](const render::material& material){
|
||||||
}
|
return std::make_shared<material_asset>(material);
|
||||||
|
});
|
||||||
content.properties(props);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_shared<material_asset>(content);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
39
sources/enduro2d/high/assets/mesh_asset.cpp
Normal file
39
sources/enduro2d/high/assets/mesh_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class mesh_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "mesh asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
mesh_asset::load_async_result mesh_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<binary_asset>(address)
|
||||||
|
.then([](const binary_asset::ptr& mesh_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw mesh_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([mesh_data](){
|
||||||
|
mesh content;
|
||||||
|
if ( !meshes::try_load_mesh(content, mesh_data->content()) ) {
|
||||||
|
throw mesh_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<mesh_asset>(std::move(content));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
124
sources/enduro2d/high/assets/shader_asset.cpp
Normal file
124
sources/enduro2d/high/assets/shader_asset.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class shader_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "shader asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* shader_asset_schema_source = R"json(
|
||||||
|
{
|
||||||
|
"type" : "object",
|
||||||
|
"required" : [ "vertex", "fragment" ],
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"vertex" : { "$ref": "#/definitions/generic_address" },
|
||||||
|
"fragment" : { "$ref": "#/definitions/generic_address" }
|
||||||
|
},
|
||||||
|
"definitions" : {
|
||||||
|
"generic_address" : {
|
||||||
|
"type" : "string",
|
||||||
|
"minLength" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})json";
|
||||||
|
|
||||||
|
const rapidjson::SchemaDocument& shader_asset_schema() {
|
||||||
|
static std::mutex mutex;
|
||||||
|
static std::unique_ptr<rapidjson::SchemaDocument> schema;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> guard(mutex);
|
||||||
|
if ( !schema ) {
|
||||||
|
rapidjson::Document doc;
|
||||||
|
if ( doc.Parse(shader_asset_schema_source).HasParseError() ) {
|
||||||
|
the<debug>().error("ASSETS: Failed to parse shader asset schema");
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
schema = std::make_unique<rapidjson::SchemaDocument>(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdex::promise<shader_ptr> parse_shader(
|
||||||
|
library& library,
|
||||||
|
str_view parent_address,
|
||||||
|
const rapidjson::Value& root)
|
||||||
|
{
|
||||||
|
E2D_ASSERT(root.HasMember("vertex") && root["vertex"].IsString());
|
||||||
|
auto vertex_p = library.load_asset_async<text_asset>(
|
||||||
|
path::combine(parent_address, root["vertex"].GetString()));
|
||||||
|
|
||||||
|
E2D_ASSERT(root.HasMember("fragment") && root["fragment"].IsString());
|
||||||
|
auto fragment_p = library.load_asset_async<text_asset>(
|
||||||
|
path::combine(parent_address, root["fragment"].GetString()));
|
||||||
|
|
||||||
|
return stdex::make_tuple_promise(std::make_tuple(
|
||||||
|
std::move(vertex_p),
|
||||||
|
std::move(fragment_p)))
|
||||||
|
.then([](const std::tuple<
|
||||||
|
text_asset::ptr,
|
||||||
|
text_asset::ptr
|
||||||
|
>& results){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_main_thread([results](){
|
||||||
|
if ( !modules::is_initialized<render>() ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
const shader_ptr content = the<render>().create_shader(
|
||||||
|
std::get<0>(results)->content(),
|
||||||
|
std::get<1>(results)->content());
|
||||||
|
if ( !content ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
shader_asset::load_async_result shader_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<json_asset>(address)
|
||||||
|
.then([
|
||||||
|
&library,
|
||||||
|
parent_address = path::parent_path(address)
|
||||||
|
](const json_asset::ptr& shader_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([shader_data](){
|
||||||
|
const rapidjson::Document& doc = shader_data->content();
|
||||||
|
rapidjson::SchemaValidator validator(shader_asset_schema());
|
||||||
|
if ( !doc.Accept(validator) ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then([&library, parent_address, shader_data](){
|
||||||
|
return parse_shader(
|
||||||
|
library, parent_address, shader_data->content());
|
||||||
|
})
|
||||||
|
.then([](const shader_ptr& shader){
|
||||||
|
if ( !shader ) {
|
||||||
|
throw shader_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<shader_asset>(shader);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
39
sources/enduro2d/high/assets/text_asset.cpp
Normal file
39
sources/enduro2d/high/assets/text_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class text_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "text asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
text_asset::load_async_result text_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
E2D_UNUSED(library);
|
||||||
|
|
||||||
|
if ( !modules::is_initialized<vfs>() ) {
|
||||||
|
return stdex::make_rejected_promise<load_result>(
|
||||||
|
text_asset_loading_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto asset_url = library.root() / address;
|
||||||
|
return the<vfs>().load_as_string_async(asset_url)
|
||||||
|
.then([](auto&& content){
|
||||||
|
return std::make_shared<text_asset>(
|
||||||
|
std::forward<decltype(content)>(content));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
43
sources/enduro2d/high/assets/texture_asset.cpp
Normal file
43
sources/enduro2d/high/assets/texture_asset.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class texture_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "texture asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
texture_asset::load_async_result texture_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<image_asset>(address)
|
||||||
|
.then([](const image_asset::ptr& texture_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw texture_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_main_thread([texture_data](){
|
||||||
|
if ( !modules::is_initialized<render>() ) {
|
||||||
|
throw texture_asset_loading_exception();
|
||||||
|
}
|
||||||
|
const texture_ptr content = the<render>().create_texture(
|
||||||
|
texture_data->content());
|
||||||
|
if ( !content ) {
|
||||||
|
throw texture_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<texture_asset>(content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
39
sources/enduro2d/high/assets/xml_asset.cpp
Normal file
39
sources/enduro2d/high/assets/xml_asset.cpp
Normal file
@@ -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 Matvey Cherevko
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "assets.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
class xml_asset_loading_exception final : public asset_loading_exception {
|
||||||
|
const char* what() const noexcept final {
|
||||||
|
return "xml asset loading exception";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
xml_asset::load_async_result xml_asset::load_async(
|
||||||
|
library& library, str_view address)
|
||||||
|
{
|
||||||
|
return library.load_asset_async<text_asset>(address)
|
||||||
|
.then([](const text_asset::ptr& xml_data){
|
||||||
|
if ( !modules::is_initialized<deferrer>() ) {
|
||||||
|
throw xml_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return the<deferrer>().do_in_worker_thread([xml_data](){
|
||||||
|
pugi::xml_document doc;
|
||||||
|
if ( !doc.load_string(xml_data->content().c_str()) ) {
|
||||||
|
throw xml_asset_loading_exception();
|
||||||
|
}
|
||||||
|
return std::make_shared<xml_asset>(std::move(doc));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,9 +84,7 @@ namespace e2d
|
|||||||
|
|
||||||
starter::starter(int argc, char *argv[], const parameters& params) {
|
starter::starter(int argc, char *argv[], const parameters& params) {
|
||||||
safe_module_initialize<engine>(argc, argv, params.engine_params());
|
safe_module_initialize<engine>(argc, argv, params.engine_params());
|
||||||
|
|
||||||
safe_module_initialize<library>(params.library_root());
|
safe_module_initialize<library>(params.library_root());
|
||||||
|
|
||||||
safe_module_initialize<asset_cache<text_asset>>(the<library>());
|
safe_module_initialize<asset_cache<text_asset>>(the<library>());
|
||||||
safe_module_initialize<asset_cache<mesh_asset>>(the<library>());
|
safe_module_initialize<asset_cache<mesh_asset>>(the<library>());
|
||||||
safe_module_initialize<asset_cache<image_asset>>(the<library>());
|
safe_module_initialize<asset_cache<image_asset>>(the<library>());
|
||||||
|
|||||||
@@ -7,68 +7,55 @@
|
|||||||
#include "_high.hpp"
|
#include "_high.hpp"
|
||||||
using namespace e2d;
|
using namespace e2d;
|
||||||
|
|
||||||
TEST_CASE("library"){
|
namespace
|
||||||
modules::initialize<vfs>();
|
{
|
||||||
modules::initialize<debug>();
|
class safe_starter_initializer final : private noncopyable {
|
||||||
//modules::initialize<window>(v2u{640,480}, "", false);
|
public:
|
||||||
//modules::initialize<render>(the<debug>(), the<window>());
|
safe_starter_initializer() {
|
||||||
modules::initialize<library>(url{"resources://bin/library"});
|
modules::initialize<starter>(0, nullptr,
|
||||||
modules::initialize<asset_cache<text_asset>>(the<library>());
|
starter::parameters(
|
||||||
modules::initialize<asset_cache<image_asset>>(the<library>());
|
engine::parameters("library_untests", "enduro2d")
|
||||||
modules::initialize<asset_cache<binary_asset>>(the<library>());
|
.without_graphics(true)));
|
||||||
{
|
}
|
||||||
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>();
|
|
||||||
|
|
||||||
|
~safe_starter_initializer() noexcept {
|
||||||
|
modules::shutdown<starter>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("library"){
|
||||||
|
safe_starter_initializer initializer;
|
||||||
|
library& l = the<library>();
|
||||||
|
{
|
||||||
auto text_res = l.load_asset<text_asset>("text_asset.txt");
|
auto text_res = l.load_asset<text_asset>("text_asset.txt");
|
||||||
REQUIRE(text_res);
|
REQUIRE(text_res);
|
||||||
REQUIRE(text_res->content() == "hello");
|
REQUIRE(text_res->content() == "hello");
|
||||||
|
|
||||||
|
auto text_res_from_cache = l.load_asset<text_asset>("text_asset.txt");
|
||||||
|
REQUIRE(text_res_from_cache);
|
||||||
|
REQUIRE(text_res_from_cache.get() == text_res.get());
|
||||||
|
|
||||||
|
the<asset_cache<text_asset>>().unload_unused_assets();
|
||||||
|
REQUIRE(the<asset_cache<text_asset>>().asset_count() == 1);
|
||||||
|
|
||||||
|
text_res.reset();
|
||||||
|
text_res_from_cache.reset();
|
||||||
|
|
||||||
|
the<deferrer>().worker().wait_all();
|
||||||
|
the<asset_cache<text_asset>>().unload_unused_assets();
|
||||||
|
REQUIRE(the<asset_cache<text_asset>>().asset_count() == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
auto binary_res = l.load_asset<binary_asset>("binary_asset.bin");
|
auto binary_res = l.load_asset<binary_asset>("binary_asset.bin");
|
||||||
REQUIRE(binary_res);
|
REQUIRE(binary_res);
|
||||||
REQUIRE(binary_res->content() == buffer("world", 5));
|
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);
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
library& l = the<library>();
|
auto empty_res = l.load_asset<binary_asset>("empty_asset");
|
||||||
|
REQUIRE_FALSE(empty_res);
|
||||||
|
}
|
||||||
|
{
|
||||||
auto image_res = l.load_asset<image_asset>("image.png");
|
auto image_res = l.load_asset<image_asset>("image.png");
|
||||||
REQUIRE(image_res);
|
REQUIRE(image_res);
|
||||||
REQUIRE(!image_res->content().empty());
|
REQUIRE(!image_res->content().empty());
|
||||||
@@ -76,107 +63,112 @@ TEST_CASE("library"){
|
|||||||
REQUIRE(the<asset_cache<image_asset>>().find("image.png"));
|
REQUIRE(the<asset_cache<image_asset>>().find("image.png"));
|
||||||
REQUIRE(the<asset_cache<binary_asset>>().find("image.png"));
|
REQUIRE(the<asset_cache<binary_asset>>().find("image.png"));
|
||||||
|
|
||||||
|
the<deferrer>().worker().wait_all();
|
||||||
the<asset_cache<binary_asset>>().unload_unused_assets();
|
the<asset_cache<binary_asset>>().unload_unused_assets();
|
||||||
REQUIRE(the<asset_cache<image_asset>>().find("image.png"));
|
REQUIRE(the<asset_cache<image_asset>>().find("image.png"));
|
||||||
REQUIRE_FALSE(the<asset_cache<binary_asset>>().find("image.png"));
|
REQUIRE_FALSE(the<asset_cache<binary_asset>>().find("image.png"));
|
||||||
|
|
||||||
image_res.reset();
|
image_res.reset();
|
||||||
|
the<deferrer>().worker().wait_all();
|
||||||
the<asset_cache<image_asset>>().unload_unused_assets();
|
the<asset_cache<image_asset>>().unload_unused_assets();
|
||||||
REQUIRE_FALSE(the<asset_cache<image_asset>>().find("image.png"));
|
REQUIRE_FALSE(the<asset_cache<image_asset>>().find("image.png"));
|
||||||
REQUIRE_FALSE(the<asset_cache<binary_asset>>().find("image.png"));
|
REQUIRE_FALSE(the<asset_cache<binary_asset>>().find("image.png"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
//library& l = the<library>();
|
if ( modules::is_initialized<render>() ) {
|
||||||
//auto shader_res = l.load_asset<shader_asset>("shader.json");
|
auto shader_res = l.load_asset<shader_asset>("shader.json");
|
||||||
//REQUIRE(shader_res);
|
REQUIRE(shader_res);
|
||||||
//REQUIRE(shader_res->content());
|
REQUIRE(shader_res->content());
|
||||||
|
|
||||||
|
auto texture_res = l.load_asset<texture_asset>("image.png");
|
||||||
|
REQUIRE(texture_res);
|
||||||
|
REQUIRE(texture_res->content());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
library& l = the<library>();
|
if ( modules::is_initialized<render>() ) {
|
||||||
auto material_res = l.load_asset<material_asset>("material.json");
|
auto material_res = l.load_asset<material_asset>("material.json");
|
||||||
REQUIRE(material_res);
|
REQUIRE(material_res);
|
||||||
{
|
{
|
||||||
const auto* sampler = material_res->content().properties().sampler("s");
|
auto texture_res = l.load_asset<texture_asset>("image.png");
|
||||||
REQUIRE(sampler);
|
REQUIRE(texture_res);
|
||||||
REQUIRE(sampler->s_wrap() == render::sampler_wrap::clamp);
|
REQUIRE(texture_res->content());
|
||||||
REQUIRE(sampler->t_wrap() == render::sampler_wrap::repeat);
|
|
||||||
REQUIRE(sampler->r_wrap() == render::sampler_wrap::mirror);
|
const auto* sampler = material_res->content().properties().sampler("s");
|
||||||
REQUIRE(sampler->min_filter() == render::sampler_min_filter::linear_mipmap_linear);
|
REQUIRE(sampler);
|
||||||
REQUIRE(sampler->mag_filter() == render::sampler_mag_filter::linear);
|
REQUIRE(sampler->s_wrap() == render::sampler_wrap::clamp);
|
||||||
|
REQUIRE(sampler->t_wrap() == render::sampler_wrap::repeat);
|
||||||
|
REQUIRE(sampler->r_wrap() == render::sampler_wrap::mirror);
|
||||||
|
REQUIRE(sampler->min_filter() == render::sampler_min_filter::linear_mipmap_linear);
|
||||||
|
REQUIRE(sampler->mag_filter() == render::sampler_mag_filter::linear);
|
||||||
|
REQUIRE(texture_res->content() == sampler->texture());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto* property = material_res->content().properties().property("i");
|
||||||
|
REQUIRE(property);
|
||||||
|
REQUIRE(property->index() == 0);
|
||||||
|
REQUIRE(stdex::get<i32>(*property) == 42);
|
||||||
|
}
|
||||||
|
REQUIRE(material_res->content().pass_count() == 1);
|
||||||
|
const auto& pass = material_res->content().pass(0);
|
||||||
|
{
|
||||||
|
const auto* property = pass.properties().property("f");
|
||||||
|
REQUIRE(property);
|
||||||
|
REQUIRE(property->index() == 1);
|
||||||
|
REQUIRE(math::approximately(stdex::get<f32>(*property), 4.2f));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto* property = pass.properties().property("v1");
|
||||||
|
REQUIRE(property);
|
||||||
|
REQUIRE(property->index() == 2);
|
||||||
|
REQUIRE(stdex::get<v2i>(*property) == v2i(1,2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto* property = pass.properties().property("v2");
|
||||||
|
REQUIRE(property);
|
||||||
|
REQUIRE(property->index() == 6);
|
||||||
|
REQUIRE(stdex::get<v3f>(*property) == v3f(3.f));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto* property = pass.properties().property("v3");
|
||||||
|
REQUIRE(property);
|
||||||
|
REQUIRE(property->index() == 4);
|
||||||
|
REQUIRE(stdex::get<v4i>(*property) == v4i(1,2,3,4));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
REQUIRE(pass.states().depth().range_near() == 1.f);
|
||||||
|
REQUIRE(pass.states().depth().range_far() == 2.f);
|
||||||
|
REQUIRE(pass.states().depth().write() == false);
|
||||||
|
REQUIRE(pass.states().depth().func() == render::compare_func::greater);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().stencil().write() == 2u);
|
||||||
|
REQUIRE(pass.states().stencil().func() == render::compare_func::never);
|
||||||
|
REQUIRE(pass.states().stencil().ref() == 4u);
|
||||||
|
REQUIRE(pass.states().stencil().mask() == 5u);
|
||||||
|
REQUIRE(pass.states().stencil().pass() == render::stencil_op::incr);
|
||||||
|
REQUIRE(pass.states().stencil().sfail() == render::stencil_op::decr);
|
||||||
|
REQUIRE(pass.states().stencil().zfail() == render::stencil_op::invert);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().culling().mode() == render::culling_mode::cw);
|
||||||
|
REQUIRE(pass.states().culling().face() == render::culling_face::front);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().capabilities().culling());
|
||||||
|
REQUIRE(pass.states().capabilities().blending());
|
||||||
|
REQUIRE(pass.states().capabilities().depth_test());
|
||||||
|
REQUIRE(pass.states().capabilities().stencil_test());
|
||||||
|
|
||||||
|
REQUIRE(pass.states().blending().constant_color() == color::white());
|
||||||
|
REQUIRE(pass.states().blending().color_mask() == render::blending_color_mask::gba);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().blending().src_rgb_factor() == render::blending_factor::dst_alpha);
|
||||||
|
REQUIRE(pass.states().blending().src_alpha_factor() == render::blending_factor::dst_alpha);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().blending().dst_rgb_factor() == render::blending_factor::dst_color);
|
||||||
|
REQUIRE(pass.states().blending().dst_alpha_factor() == render::blending_factor::src_color);
|
||||||
|
|
||||||
|
REQUIRE(pass.states().blending().rgb_equation() == render::blending_equation::subtract);
|
||||||
|
REQUIRE(pass.states().blending().alpha_equation() == render::blending_equation::reverse_subtract);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
|
||||||
const auto* property = material_res->content().properties().property("i");
|
|
||||||
REQUIRE(property);
|
|
||||||
REQUIRE(property->index() == 0);
|
|
||||||
REQUIRE(stdex::get<i32>(*property) == 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(material_res->content().pass_count() == 1);
|
|
||||||
const auto& pass = material_res->content().pass(0);
|
|
||||||
//REQUIRE(pass.shader());
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto* property = pass.properties().property("f");
|
|
||||||
REQUIRE(property);
|
|
||||||
REQUIRE(property->index() == 1);
|
|
||||||
REQUIRE(math::approximately(stdex::get<f32>(*property), 4.2f));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const auto* property = pass.properties().property("v1");
|
|
||||||
REQUIRE(property);
|
|
||||||
REQUIRE(property->index() == 2);
|
|
||||||
REQUIRE(stdex::get<v2i>(*property) == v2i(1,2));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const auto* property = pass.properties().property("v2");
|
|
||||||
REQUIRE(property);
|
|
||||||
REQUIRE(property->index() == 6);
|
|
||||||
REQUIRE(stdex::get<v3f>(*property) == v3f(3.f));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const auto* property = pass.properties().property("v3");
|
|
||||||
REQUIRE(property);
|
|
||||||
REQUIRE(property->index() == 4);
|
|
||||||
REQUIRE(stdex::get<v4i>(*property) == v4i(1,2,3,4));
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(pass.states().depth().range_near() == 1.f);
|
|
||||||
REQUIRE(pass.states().depth().range_far() == 2.f);
|
|
||||||
REQUIRE(pass.states().depth().write() == false);
|
|
||||||
REQUIRE(pass.states().depth().func() == render::compare_func::greater);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().stencil().write() == 2u);
|
|
||||||
REQUIRE(pass.states().stencil().func() == render::compare_func::never);
|
|
||||||
REQUIRE(pass.states().stencil().ref() == 4u);
|
|
||||||
REQUIRE(pass.states().stencil().mask() == 5u);
|
|
||||||
REQUIRE(pass.states().stencil().pass() == render::stencil_op::incr);
|
|
||||||
REQUIRE(pass.states().stencil().sfail() == render::stencil_op::decr);
|
|
||||||
REQUIRE(pass.states().stencil().zfail() == render::stencil_op::invert);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().culling().mode() == render::culling_mode::cw);
|
|
||||||
REQUIRE(pass.states().culling().face() == render::culling_face::front);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().capabilities().culling());
|
|
||||||
REQUIRE(pass.states().capabilities().blending());
|
|
||||||
REQUIRE(pass.states().capabilities().depth_test());
|
|
||||||
REQUIRE(pass.states().capabilities().stencil_test());
|
|
||||||
|
|
||||||
REQUIRE(pass.states().blending().constant_color() == color::white());
|
|
||||||
REQUIRE(pass.states().blending().color_mask() == render::blending_color_mask::gba);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().blending().src_rgb_factor() == render::blending_factor::dst_alpha);
|
|
||||||
REQUIRE(pass.states().blending().src_alpha_factor() == render::blending_factor::dst_alpha);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().blending().dst_rgb_factor() == render::blending_factor::dst_color);
|
|
||||||
REQUIRE(pass.states().blending().dst_alpha_factor() == render::blending_factor::src_color);
|
|
||||||
|
|
||||||
REQUIRE(pass.states().blending().rgb_equation() == render::blending_equation::subtract);
|
|
||||||
REQUIRE(pass.states().blending().alpha_equation() == render::blending_equation::reverse_subtract);
|
|
||||||
}
|
}
|
||||||
modules::shutdown<asset_cache<binary_asset>>();
|
|
||||||
modules::shutdown<asset_cache<image_asset>>();
|
|
||||||
modules::shutdown<asset_cache<text_asset>>();
|
|
||||||
modules::shutdown<library>();
|
|
||||||
modules::shutdown<debug>();
|
|
||||||
modules::shutdown<vfs>();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user