atlas resource first impl

This commit is contained in:
2019-03-21 09:29:57 +07:00
parent 6e0e2921b1
commit cdb15dd58d
5 changed files with 346 additions and 8 deletions

View File

@@ -8,9 +8,23 @@
#include "_high.hpp"
#include "assets/texture_asset.hpp"
namespace e2d
{
class atlas final {
public:
struct region {
str_hash name;
v2f pivot;
b2f texrect;
};
struct shape_region {
str_hash name;
v2f pivot;
vector<v2f> points;
};
public:
atlas();
~atlas() noexcept;
@@ -26,9 +40,38 @@ namespace e2d
atlas& assign(atlas&& other) noexcept;
atlas& assign(const atlas& other);
atlas& set_texture(const texture_asset::ptr& texture) noexcept;
const texture_asset::ptr& texture() const noexcept;
atlas& set_pixels_per_unit(f32 pixels_per_unit) noexcept;
f32 pixels_per_unit() const noexcept;
atlas& set_regions(vector<region>&& regions) noexcept;
atlas& set_regions(const vector<region>& regions);
const vector<region>& regions() const noexcept;
const region* find_region(str_hash name) const noexcept;
atlas& set_shape_regions(vector<shape_region>&& regions) noexcept;
atlas& set_shape_regions(const vector<shape_region>& regions);
const vector<shape_region>& shape_regions() const noexcept;
const shape_region* find_shape_region(str_hash name) const noexcept;
private:
texture_asset::ptr texture_;
f32 pixels_per_unit_{1.f};
vector<region> regions_;
vector<shape_region> shape_regions_;
};
void swap(atlas& l, atlas& r) noexcept;
bool operator==(const atlas& l, const atlas& r) noexcept;
bool operator!=(const atlas& l, const atlas& r) noexcept;
void swap(atlas::region& l, atlas::region& r) noexcept;
bool operator==(const atlas::region& l, const atlas::region& r) noexcept;
bool operator!=(const atlas::region& l, const atlas::region& r) noexcept;
void swap(atlas::shape_region& l, atlas::shape_region& r) noexcept;
bool operator==(const atlas::shape_region& l, const atlas::shape_region& r) noexcept;
bool operator!=(const atlas::shape_region& l, const atlas::shape_region& r) noexcept;
}

View File

@@ -21,10 +21,47 @@ namespace
const char* atlas_asset_schema_source = R"json(
{
"type" : "object",
"required" : [ "texture" ],
"required" : [ "texture", "pixels_per_unit" ],
"additionalProperties" : false,
"properties" : {
"texture" : { "$ref": "#/common_definitions/address" }
"texture" : { "$ref": "#/common_definitions/address" },
"pixels_per_unit" : { "type" : "number" },
"regions" : { "$ref": "#/definitions/regions" },
"shape_regions" : { "$ref": "#/definitions/shape_regions" }
},
"definitions" : {
"regions" : {
"type" : "array",
"items" : { "$ref": "#/definitions/region" }
},
"region" : {
"type" : "object",
"required" : [ "name", "pivot", "texrect" ],
"additionalProperties" : false,
"properties" : {
"name" : { "$ref": "#/common_definitions/name" },
"pivot" : { "$ref": "#/common_definitions/v2" },
"texrect" : { "$ref": "#/common_definitions/b2" }
}
},
"shape_regions" : {
"type" : "array",
"items" : { "$ref": "#/definitions/shape_region" }
},
"shape_region" : {
"type" : "object",
"required" : [ "name", "pivot", "points" ],
"additionalProperties" : false,
"properties" : {
"name" : { "$ref": "#/common_definitions/name" },
"pivot" : { "$ref": "#/common_definitions/v2" },
"points" : {
"type" : "array",
"minItems" : 3,
"items" : { "$ref": "#/common_definitions/v2" }
}
}
}
}
})json";
@@ -46,13 +83,116 @@ namespace
return *schema;
}
bool parse_regions(
const rapidjson::Value& root,
vector<atlas::region>& regions)
{
E2D_ASSERT(root.IsArray());
vector<atlas::region> tregions(root.Size());
for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) {
E2D_ASSERT(root[i].IsObject());
const auto& region_json = root[i];
E2D_ASSERT(region_json.HasMember("name"));
if ( !json_utils::try_parse_value(region_json["name"], tregions[i].name) ) {
return false;
}
E2D_ASSERT(region_json.HasMember("pivot"));
if ( !json_utils::try_parse_value(region_json["pivot"], tregions[i].pivot) ) {
return false;
}
E2D_ASSERT(region_json.HasMember("texrect"));
if ( !json_utils::try_parse_value(region_json["texrect"], tregions[i].texrect) ) {
return false;
}
}
regions = std::move(tregions);
return true;
}
bool parse_shape_regions(
const rapidjson::Value& root,
vector<atlas::shape_region>& regions)
{
E2D_ASSERT(root.IsArray());
vector<atlas::shape_region> tregions(root.Size());
for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) {
E2D_ASSERT(root[i].IsObject());
const auto& region_json = root[i];
E2D_ASSERT(region_json.HasMember("name"));
if ( !json_utils::try_parse_value(region_json["name"], tregions[i].name) ) {
return false;
}
E2D_ASSERT(region_json.HasMember("pivot"));
if ( !json_utils::try_parse_value(region_json["pivot"], tregions[i].pivot) ) {
return false;
}
E2D_ASSERT(region_json.HasMember("points"));
if ( !json_utils::try_parse_values(region_json["points"], tregions[i].points) ) {
return false;
}
}
regions = std::move(tregions);
return true;
}
stdex::promise<atlas> parse_atlas(
library& library,
str_view parent_address,
const rapidjson::Value& root)
{
E2D_UNUSED(library, parent_address, root);
return stdex::make_resolved_promise<atlas>(atlas());
E2D_ASSERT(root.HasMember("texture") && root["texture"].IsString());
auto texture_p = library.load_asset_async<texture_asset>(
path::combine(parent_address, root["texture"].GetString()));
f32 pixels_per_unit = 1.f;
E2D_ASSERT(root.HasMember("pixels_per_unit"));
if ( !json_utils::try_parse_value(root["pixels_per_unit"], pixels_per_unit) ) {
return stdex::make_rejected_promise<atlas>(
atlas_asset_loading_exception());
}
vector<atlas::region> regions;
if ( root.HasMember("regions") ) {
E2D_ASSERT(root["regions"].IsArray());
const auto& regions_json = root["regions"];
if ( !parse_regions(regions_json, regions) ) {
return stdex::make_rejected_promise<atlas>(
atlas_asset_loading_exception());
}
}
vector<atlas::shape_region> shape_regions;
if ( root.HasMember("shape_regions") ) {
E2D_ASSERT(root["shape_regions"].IsArray());
const auto& shape_regions_json = root["shape_regions"];
if ( !parse_shape_regions(shape_regions_json, shape_regions) ) {
return stdex::make_rejected_promise<atlas>(
atlas_asset_loading_exception());
}
}
return texture_p.then([
pixels_per_unit,
regions = std::move(regions),
shape_regions = std::move(shape_regions)
](const texture_asset::load_result& texture) mutable {
atlas content;
content.set_texture(texture);
content.set_pixels_per_unit(pixels_per_unit);
content.set_regions(std::move(regions));
content.set_shape_regions(std::move(shape_regions));
return content;
});
}
}

View File

@@ -28,11 +28,18 @@ namespace e2d
}
void atlas::clear() noexcept {
texture_.reset();
pixels_per_unit_ = 1.f;
regions_.clear();
shape_regions_.clear();
}
void atlas::swap(atlas& other) noexcept {
using std::swap;
E2D_UNUSED(other);
swap(texture_, other.texture_);
swap(pixels_per_unit_, other.pixels_per_unit_);
swap(regions_, other.regions_);
swap(shape_regions_, other.shape_regions_);
}
atlas& atlas::assign(atlas&& other) noexcept {
@@ -46,10 +53,90 @@ namespace e2d
atlas& atlas::assign(const atlas& other) {
if ( this != &other ) {
atlas s;
s.texture_ = other.texture_;
s.pixels_per_unit_ = other.pixels_per_unit_;
s.regions_ = other.regions_;
s.shape_regions_ = other.shape_regions_;
swap(s);
}
return *this;
}
atlas& atlas::set_texture(const texture_asset::ptr& texture) noexcept {
texture_ = texture;
return *this;
}
const texture_asset::ptr& atlas::texture() const noexcept {
return texture_;
}
atlas& atlas::set_pixels_per_unit(f32 pixels_per_unit) noexcept {
pixels_per_unit_ = pixels_per_unit;
return *this;
}
f32 atlas::pixels_per_unit() const noexcept {
return pixels_per_unit_;
}
atlas& atlas::set_regions(vector<region>&& regions) noexcept {
regions_ = std::move(regions);
std::sort(
regions_.begin(), regions_.end(),
[](const atlas::region& l, const atlas::region& r) noexcept {
return l.name < r.name;
});
return *this;
}
atlas& atlas::set_regions(const vector<region>& regions) {
return set_regions(vector<region>(regions));
}
const vector<atlas::region>& atlas::regions() const noexcept {
return regions_;
}
const atlas::region* atlas::find_region(str_hash name) const noexcept {
const auto iter = std::lower_bound(
regions_.begin(), regions_.end(), name,
[](const atlas::region& l, str_hash r) noexcept {
return l.name < r;
});
return iter != regions_.end() && iter->name == name
? &*iter
: nullptr;
}
atlas& atlas::set_shape_regions(vector<shape_region>&& regions) noexcept {
shape_regions_ = std::move(regions);
std::sort(
shape_regions_.begin(), shape_regions_.end(),
[](const atlas::shape_region& l, const atlas::shape_region& r) noexcept {
return l.name < r.name;
});
return *this;
}
atlas& atlas::set_shape_regions(const vector<shape_region>& regions) {
return set_shape_regions(vector<shape_region>(regions));
}
const vector<atlas::shape_region>& atlas::shape_regions() const noexcept {
return shape_regions_;
}
const atlas::shape_region* atlas::find_shape_region(str_hash name) const noexcept {
const auto iter = std::lower_bound(
shape_regions_.begin(), shape_regions_.end(), name,
[](const atlas::shape_region& l, str_hash r) noexcept {
return l.name < r;
});
return iter != shape_regions_.end() && iter->name == name
? &*iter
: nullptr;
}
}
namespace e2d
@@ -59,11 +146,47 @@ namespace e2d
}
bool operator==(const atlas& l, const atlas& r) noexcept {
E2D_UNUSED(l, r);
return true;
return l.texture() == r.texture()
&& math::approximately(l.pixels_per_unit(), r.pixels_per_unit())
&& l.regions() == r.regions()
&& l.shape_regions() == r.shape_regions();
}
bool operator!=(const atlas& l, const atlas& r) noexcept {
return !(l == r);
}
void swap(atlas::region& l, atlas::region& r) noexcept {
using std::swap;
swap(l.name, r.name);
swap(l.pivot, r.pivot);
swap(l.texrect, r.texrect);
}
bool operator==(const atlas::region& l, const atlas::region& r) noexcept {
return l.name == r.name
&& l.pivot == r.pivot
&& l.texrect == r.texrect;
}
bool operator!=(const atlas::region& l, const atlas::region& r) noexcept {
return !(l == r);
}
void swap(atlas::shape_region& l, atlas::shape_region& r) noexcept {
using std::swap;
swap(l.name, r.name);
swap(l.pivot, r.pivot);
swap(l.points, r.points);
}
bool operator==(const atlas::shape_region& l, const atlas::shape_region& r) noexcept {
return l.name == r.name
&& l.pivot == r.pivot
&& l.points == r.points;
}
bool operator!=(const atlas::shape_region& l, const atlas::shape_region& r) noexcept {
return !(l == r);
}
}

View File

@@ -1,3 +1,17 @@
{
"texture" : "image.png"
"texture" : "image.png",
"pixels_per_unit" : 2,
"regions" : [{
"name" : "sprite",
"pivot" : { "x" : 1, "y" : 2 },
"texrect" : { "x" : 5, "y" : 6, "w" : 7, "h" : 8 }
}],
"shape_regions" : [{
"name" : "shape_sprite",
"pivot" : { "x" : 3, "y" : 4 },
"points" : [
{ "x" : 1, "y" : 2 },
{ "x" : 3, "y" : 4 },
{ "x" : 5, "y" : 6 }]
}]
}

View File

@@ -98,6 +98,24 @@ TEST_CASE("library"){
auto atlas_res = l.load_asset<atlas_asset>("atlas.json");
REQUIRE(atlas_res);
REQUIRE(atlas_res->content().texture() == texture_res);
REQUIRE(math::approximately(atlas_res->content().pixels_per_unit(), 2.f));
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>{
{1.f, 2.f},
{3.f, 4.f},
{5.f, 6.f}
});
REQUIRE_FALSE(atlas_res->content().find_shape_region("shape_sprite2"));
auto sprite_res = l.load_asset<sprite_asset>("sprite.json");
REQUIRE(sprite_res);