Merge pull request #123 from enduro2d/feature/prefab_children_mod

Feature/prefab children mod
This commit is contained in:
2020-04-24 20:24:42 +07:00
committed by GitHub
29 changed files with 1007 additions and 194 deletions

View File

@@ -85,6 +85,10 @@ namespace e2d
bool add_child(
const node_iptr& child) noexcept;
bool add_child_at(
const node_iptr& child,
std::size_t index) noexcept;
bool add_child_to_back(
const node_iptr& child) noexcept;
@@ -108,6 +112,17 @@ namespace e2d
bool remove_child(
const node_iptr& child) noexcept;
node_iptr remove_child_at(
std::size_t index) noexcept;
bool swap_children(
const node_iptr& child_l,
const node_iptr& child_r) noexcept;
bool swap_children_at(
std::size_t child_l,
std::size_t child_r) noexcept;
bool send_backward() noexcept;
bool bring_to_back() noexcept;
@@ -125,6 +140,12 @@ namespace e2d
node_iptr next_sibling() noexcept;
const_node_iptr next_sibling() const noexcept;
node_iptr child_at(std::size_t index) noexcept;
const_node_iptr child_at(std::size_t index) const noexcept;
std::pair<std::size_t, bool> child_index(
const const_node_iptr& child) const noexcept;
protected:
node() = default;
node(gobject owner);

View File

@@ -27,22 +27,30 @@ namespace e2d
prefab& assign(prefab&& other) noexcept;
prefab& assign(const prefab& other);
prefab& set_prototype(ecs::prototype&& proto) noexcept;
prefab& set_prototype(const ecs::prototype& proto);
prefab& set_uuid(str&& uuid) noexcept;
prefab& set_uuid(const str& uuid);
prefab& set_children(vector<prefab>&& children) noexcept;
prefab& set_children(const vector<prefab>& children);
prefab& set_prototype(ecs::prototype&& prototype) noexcept;
prefab& set_prototype(const ecs::prototype& prototype);
str& uuid() noexcept;
const str& uuid() const noexcept;
vector<prefab>& children() noexcept;
const vector<prefab>& children() const noexcept;
ecs::prototype& prototype() noexcept;
const ecs::prototype& prototype() const noexcept;
const vector<prefab>& children() const noexcept;
private:
ecs::prototype prototype_;
str uuid_;
vector<prefab> children_;
ecs::prototype prototype_;
};
void swap(prefab& l, prefab& r) noexcept;
bool operator==(const prefab& l, const prefab& r) noexcept;
bool operator!=(const prefab& l, const prefab& r) noexcept;
bool operator==(const prefab& l, const prefab& r) = delete;
bool operator!=(const prefab& l, const prefab& r) = delete;
}

View File

@@ -109,6 +109,20 @@ namespace e2d
swap_next(l, r);
}
}
static void transfer_nodes(node_ptr p, node_ptr b, node_ptr e) noexcept {
if ( b != e ) {
node_ptr prev_p = p->prev_;
node_ptr prev_b = b->prev_;
node_ptr prev_e = e->prev_;
prev_e->next_ = p;
p->prev_ = prev_e;
prev_b->next_ = e;
e->prev_ = prev_b;
prev_p->next_ = b;
b->prev_ = prev_p;
}
}
private:
node_ptr prev_{nullptr};
node_ptr next_{nullptr};
@@ -252,15 +266,15 @@ namespace e2d
void swap(intrusive_list& other) noexcept;
template < typename Disposer >
void clear_and_dispose(Disposer&& disposer);
void clear_and_dispose(Disposer disposer);
void clear() noexcept;
template < typename Disposer >
void pop_back_and_dispose(Disposer&& disposer);
void pop_back_and_dispose(Disposer disposer);
void pop_back() noexcept;
template < typename Disposer >
void pop_front_and_dispose(Disposer&& disposer);
void pop_front_and_dispose(Disposer disposer);
void pop_front() noexcept;
void push_back(T& v) noexcept;
@@ -268,11 +282,24 @@ namespace e2d
iterator insert(const_iterator pos, T& v) noexcept;
template < typename Disposer >
iterator erase_and_dispose(const_iterator pos, Disposer&& disposer);
iterator erase_and_dispose(const_iterator pos, Disposer disposer);
iterator erase(const_iterator pos) noexcept;
void splice(const_iterator pos, intrusive_list& x) noexcept;
void splice(const_iterator pos, const_iterator f, const_iterator e) noexcept;
template < typename Predicate >
void merge(intrusive_list& x, Predicate predicate);
void merge(intrusive_list& x);
template < typename Predicate >
void sort(Predicate predicate);
void sort();
static iterator iterator_to(T& v) noexcept;
static const_iterator iterator_to(const T& v) noexcept;
static void iterator_swap(iterator l, iterator r) noexcept;
private:
using node_t = intrusive_list_hook<Tag>;
using node_ptr = typename node_t::node_ptr;
@@ -406,7 +433,7 @@ namespace e2d
template < typename T, typename Tag >
template < typename Disposer >
void intrusive_list<T,Tag>::clear_and_dispose(Disposer&& disposer) {
void intrusive_list<T,Tag>::clear_and_dispose(Disposer disposer) {
while ( !empty() ) {
pop_back_and_dispose(disposer);
}
@@ -419,7 +446,7 @@ namespace e2d
template < typename T, typename Tag >
template < typename Disposer >
void intrusive_list<T,Tag>::pop_back_and_dispose(Disposer&& disposer) {
void intrusive_list<T,Tag>::pop_back_and_dispose(Disposer disposer) {
E2D_ASSERT(!empty());
node_ptr node = root_.prev_;
node->unlink();
@@ -433,7 +460,7 @@ namespace e2d
template < typename T, typename Tag >
template < typename Disposer >
void intrusive_list<T,Tag>::pop_front_and_dispose(Disposer&& disposer) {
void intrusive_list<T,Tag>::pop_front_and_dispose(Disposer disposer) {
E2D_ASSERT(!empty());
node_ptr node = root_.next_;
node->unlink();
@@ -469,7 +496,7 @@ namespace e2d
template < typename T, typename Tag >
template < typename Disposer >
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::erase_and_dispose(const_iterator pos, Disposer&& disposer) {
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::erase_and_dispose(const_iterator pos, Disposer disposer) {
node_ptr node = pos.node();
E2D_ASSERT(node != &root_ && node->is_linked());
++pos;
@@ -483,6 +510,70 @@ namespace e2d
return erase_and_dispose(pos, null_disposer());
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::splice(const_iterator pos, intrusive_list& x) noexcept {
intrusive_list_hook<Tag>::transfer_nodes(pos.node(), x.begin().node(), x.end().node());
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::splice(const_iterator pos, const_iterator f, const_iterator e) noexcept {
intrusive_list_hook<Tag>::transfer_nodes(pos.node(), f.node(), e.node());
}
template < typename T, typename Tag >
template < typename Predicate >
void intrusive_list<T,Tag>::merge(intrusive_list& x, Predicate predicate) {
const_iterator b(cbegin()), e(cend()), ex(x.cend());
while ( !x.empty() ) {
const_iterator ix(x.cbegin());
while ( b != e && !predicate(*ix, *b) ) {
++b;
}
if ( b == e ) {
splice(e, x);
break;
} else {
do {
++ix;
} while ( ix != ex && predicate(*ix, *b) );
splice(b, x.begin(), ix);
}
}
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::merge(intrusive_list& x) {
merge(x, std::less<value_type>());
}
template < typename T, typename Tag >
template < typename Predicate >
void intrusive_list<T,Tag>::sort(Predicate predicate) {
if ( root_.next_ != &root_ && root_.next_ != root_.prev_ ) {
intrusive_list left_list;
intrusive_list right_list;
const_iterator mid(cbegin()), tail(cend());
while ( (mid != tail) && (++mid != tail) ) {
--tail;
}
left_list.splice(left_list.cbegin(), cbegin(), mid);
right_list.splice(right_list.cbegin(), *this);
left_list.sort(predicate);
right_list.sort(predicate);
splice(cbegin(), left_list);
merge(right_list, predicate);
}
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::sort() {
sort(std::less<value_type>());
}
template < typename T, typename Tag >
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::iterator_to(T& v) noexcept {
node_t& node = static_cast<node_t&>(v);
@@ -496,4 +587,10 @@ namespace e2d
E2D_ASSERT(node.is_linked());
return const_iterator(&node);
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::iterator_swap(iterator l, iterator r) noexcept {
E2D_ASSERT(l.node()->is_linked() && r.node()->is_linked());
intrusive_list_hook<Tag>::swap_nodes(l.node(), r.node());
}
}

View File

@@ -5,7 +5,7 @@
}
},
"children" : [{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [-512,0]
@@ -15,7 +15,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [-256,0]
@@ -25,7 +25,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [0,0]
@@ -35,7 +35,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [256,0]
@@ -45,7 +45,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [-512,-256]
@@ -55,7 +55,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [-256,-256]
@@ -65,7 +65,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [0,-256]
@@ -75,7 +75,7 @@
}
}
},{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"actor" : {
"translation" : [256,-256]

View File

@@ -1,5 +1,5 @@
{
"prototype" : "spine_prefab.json",
"prefab" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "coin"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "spine_prefab.json",
"prefab" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "dragon"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "model_prefab.json",
"prefab" : "model_prefab.json",
"components" : {
"named" : {
"name" : "gnome"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "widget_prefab.json",
"prefab" : "widget_prefab.json",
"components" : {
"named" : {
"name" : "layout"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"named" : {
"name" : "panel"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "spine_prefab.json",
"prefab" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "raptor"

View File

@@ -1,5 +1,5 @@
{
"prototype" : "sprite_prefab.json",
"prefab" : "sprite_prefab.json",
"components" : {
"named" : {
"name" : "ship"

View File

@@ -1,7 +1,7 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"prefab" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : 0.5
@@ -14,7 +14,7 @@
}
}
},{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : -0.5
@@ -27,7 +27,7 @@
}
}
},{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : 0.5
@@ -40,7 +40,7 @@
}
}
},{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : -0.5
@@ -53,7 +53,7 @@
}
}
},{
"prototype" : "../prefabs/gnome_prefab.json",
"prefab" : "../prefabs/gnome_prefab.json",
"components" : {
"actor" : {
"translation" : [0,0],
@@ -64,7 +64,7 @@
}
}
}, {
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"sprite_renderer" : {
"blending" : "additive"
@@ -77,7 +77,7 @@
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"sprite_renderer" : {
"tint" : [255,0,0,255]
@@ -91,7 +91,7 @@
}
}]
}, {
"prototype" : "../prefabs/label_bm_prefab.json",
"prefab" : "../prefabs/label_bm_prefab.json",
"components" : {
"label" : {
"text" : "bm font",
@@ -108,7 +108,7 @@
}
}
}, {
"prototype" : "../prefabs/label_sdf_prefab.json",
"prefab" : "../prefabs/label_sdf_prefab.json",
"components" : {
"label" : {
"text" : "sdf font",

View File

@@ -1,9 +1,9 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"prefab" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/camera_prefab.json"
"prefab" : "../prefabs/camera_prefab.json"
},{
"prototype" : "../prefabs/coin_prefab.json",
"prefab" : "../prefabs/coin_prefab.json",
"components" : {
"actor" : {
"translation" : [350,250],
@@ -14,7 +14,7 @@
}
}
}, {
"prototype" : "../prefabs/raptor_prefab.json",
"prefab" : "../prefabs/raptor_prefab.json",
"components" : {
"actor" : {
"translation" : [300,-350],
@@ -25,7 +25,7 @@
}
}
}, {
"prototype" : "../prefabs/dragon_prefab.json",
"prefab" : "../prefabs/dragon_prefab.json",
"components" : {
"actor" : {
"translation" : [-100,0],

View File

@@ -1,16 +1,16 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"prefab" : "../prefabs/scene_prefab.json",
"components" : {
"behaviour" : {
"script" : "../scripts/sample_07/sample_07.lua"
}
},
"children" : [{
"prototype" : "../prefabs/camera_prefab.json"
"prefab" : "../prefabs/camera_prefab.json"
},{
"prototype" : "../prefabs/background_prefab.json"
"prefab" : "../prefabs/background_prefab.json"
},{
"prototype" : "../prefabs/gnome_prefab.json",
"prefab" : "../prefabs/gnome_prefab.json",
"components" : {
"actor" : {
"translation" : [0,0],
@@ -21,7 +21,7 @@
}
}
},{
"prototype" : "../prefabs/label_sdf_prefab.json",
"prefab" : "../prefabs/label_sdf_prefab.json",
"components" : {
"label" : {
"text" : "FPS: ",

View File

@@ -1,12 +1,12 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"prefab" : "../prefabs/scene_prefab.json",
"components" : {
"behaviour" : {
"script" : "../scripts/sample_08/sample_08.lua"
}
},
"children" : [{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : 0.5
@@ -19,7 +19,7 @@
}
}
},{
"prototype" : "../prefabs/camera_prefab.json",
"prefab" : "../prefabs/camera_prefab.json",
"components" : {
"actor" : {
"rotation" : -0.5
@@ -32,7 +32,7 @@
}
}
},{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"named" : {
"name" : "ship(1)"
@@ -51,7 +51,7 @@
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"named" : {
"name" : "ship(11)"
@@ -69,11 +69,10 @@
"offset" : [10,15],
"radius" : 33
}
},
"children" : []
}
}]
},{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"named" : {
"name" : "ship(2)"
@@ -113,7 +112,7 @@
}
}
},{
"prototype" : "../prefabs/label_sdf_prefab.json",
"prefab" : "../prefabs/label_sdf_prefab.json",
"components" : {
"named" : {
"name" : "label"

View File

@@ -1,18 +1,18 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"prefab" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/background_prefab.json"
"prefab" : "../prefabs/background_prefab.json"
},{
"prototype" : "../prefabs/camera_prefab.json"
"prefab" : "../prefabs/camera_prefab.json"
},{
"prototype" : "../prefabs/panel_prefab.json",
"prefab" : "../prefabs/panel_prefab.json",
"components" : {
"sprite_renderer" : {
"scale" : [4,2]
}
},
"children" : [{
"prototype" : "../prefabs/layout_prefab.json",
"prefab" : "../prefabs/layout_prefab.json",
"components" : {
"layout" : {
"justify_content" : "space_evenly"
@@ -22,14 +22,14 @@
}
},
"children" : [{
"prototype" : "../prefabs/widget_prefab.json",
"prefab" : "../prefabs/widget_prefab.json",
"components" : {
"widget" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]
@@ -37,14 +37,14 @@
}
}]
},{
"prototype" : "../prefabs/widget_prefab.json",
"prefab" : "../prefabs/widget_prefab.json",
"components" : {
"widget" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]
@@ -52,14 +52,14 @@
}
}]
},{
"prototype" : "../prefabs/widget_prefab.json",
"prefab" : "../prefabs/widget_prefab.json",
"components" : {
"widget" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"prefab" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]

View File

@@ -87,6 +87,12 @@ function node.remove_all_children(self) end
---@return boolean
function node.add_child(self, child) end
---@param self node
---@param child node
---@param index integer
---@return boolean
function node.add_child_at(self, child, index) end
---@param self node
---@param child node
---@return boolean
@@ -124,6 +130,23 @@ function node.add_sibling_after(self, sibling) end
---@return boolean
function node.remove_child(self, child) end
---@param self node
---@param index integer
---@return node
function node.remove_child_at(self, index) end
---@param self node
---@param child_l node
---@param child_r node
---@return boolean
function node.swap_children(self, child_l, child_r) end
---@param self node
---@param child_l integer
---@param child_r integer
---@return boolean
function node.swap_children_at(self, child_l, child_r) end
---@param self node
---@return boolean
function node.send_backward(self) end
@@ -140,5 +163,15 @@ function node.send_forward(self) end
---@return boolean
function node.bring_to_front(self) end
---@param self node
---@param index integer
---@return node
function node.child_at(self, index) end
---@param self node
---@param child node
---@return integer, boolean
function node.child_index(self, child) end
---@type node
_G.node = _G.node or node

View File

@@ -24,25 +24,42 @@ namespace
"required" : [],
"additionalProperties" : false,
"properties" : {
"prototype" : { "$ref": "#/common_definitions/address" },
"components" : { "type" : "object" },
"uuid" : { "$ref": "#/common_definitions/uuid" },
"prefab" : { "$ref": "#/common_definitions/address" },
"children" : { "$ref": "#/definitions/children" },
"mod_children" : { "$ref": "#/definitions/mod_children" },
"components" : { "type" : "object" }
},
"definitions" : {
"children" : {
"type" : "array",
"items" : { "$ref": "#/definitions/child" }
}
},
"definitions" : {
},
"child" : {
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {
"prototype" : { "$ref": "#/common_definitions/address" },
"components" : { "type" : "object" },
"children" : {
"type" : "array",
"items" : { "$ref": "#/definitions/child" }
}
"uuid" : { "$ref": "#/common_definitions/uuid" },
"prefab" : { "$ref": "#/common_definitions/address" },
"children" : { "$ref": "#/definitions/children" },
"mod_children" : { "$ref": "#/definitions/mod_children" },
"components" : { "type" : "object" }
}
},
"mod_children" : {
"type" : "array",
"items" : { "$ref": "#/definitions/mod_child" }
},
"mod_child" : {
"type" : "object",
"required" : [ "uuid" ],
"additionalProperties" : false,
"properties" : {
"uuid" : { "$ref": "#/common_definitions/uuid" },
"children" : { "$ref": "#/definitions/children" },
"mod_children" : { "$ref": "#/definitions/mod_children" },
"components" : { "type" : "object" }
}
}
}
@@ -71,9 +88,23 @@ namespace
const rapidjson::Value& root,
asset_dependencies& dependencies)
{
if ( root.HasMember("prototype") ) {
if ( root.HasMember("prefab") ) {
dependencies.add_dependency<prefab_asset>(
path::combine(parent_address, root["prototype"].GetString()));
path::combine(parent_address, root["prefab"].GetString()));
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
collect_dependencies(parent_address, children_root[i], dependencies);
}
}
if ( root.HasMember("mod_children") ) {
const rapidjson::Value& mod_children_root = root["mod_children"];
for ( rapidjson::SizeType i = 0; i < mod_children_root.Size(); ++i ) {
collect_dependencies(parent_address, mod_children_root[i], dependencies);
}
}
if ( root.HasMember("components") ) {
@@ -83,9 +114,10 @@ namespace
++component_root )
{
{
bool success = the<factory>().validate_json(
const bool success = the<factory>().validate_json(
component_root->name.GetString(),
component_root->value);
if ( !success ) {
throw prefab_asset_loading_exception();
}
@@ -94,23 +126,18 @@ namespace
factory_loader<>::collect_context ctx(
str(parent_address),
component_root->value);
bool success = the<factory>().collect_dependencies(
const bool success = the<factory>().collect_dependencies(
component_root->name.GetString(),
dependencies,
ctx);
if ( !success ) {
throw prefab_asset_loading_exception();
}
}
}
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
collect_dependencies(parent_address, children_root[i], dependencies);
}
}
}
stdex::promise<asset_group> collect_dependencies(
@@ -123,25 +150,92 @@ namespace
return dependencies.load_async(library);
}
prefab parse_prefab(
prefab* find_prefab_child(prefab& root, str_view child_uuid) noexcept {
for ( prefab& child : root.children() ) {
if ( child.uuid() == child_uuid ) {
return &child;
}
}
for ( prefab& child : root.children() ) {
if ( prefab* sub_child = find_prefab_child(child, child_uuid) ) {
return sub_child;
}
}
return nullptr;
}
void parse_prefab_inplace(
prefab& content,
str_view parent_address,
const rapidjson::Value& root,
const asset_group& dependencies)
{
prefab content;
if ( root.HasMember("uuid") ) {
str uuid = root["uuid"].GetString();
content.set_uuid(std::move(uuid));
}
if ( root.HasMember("prototype") ) {
if ( root.HasMember("prefab") ) {
auto proto_res = dependencies.find_asset<prefab_asset>(
path::combine(parent_address, root["prototype"].GetString()));
path::combine(parent_address, root["prefab"].GetString()));
if ( !proto_res ) {
the<debug>().error("PREFAB: Dependency 'prototype' is not found:\n"
the<debug>().error("PREFAB: Dependency 'prefab' is not found:\n"
"--> Parent address: %0\n"
"--> Dependency address: %1",
parent_address,
root["prototype"].GetString());
root["prefab"].GetString());
throw prefab_asset_loading_exception();
}
content = proto_res->content();
content.set_children(proto_res->content().children());
content.set_prototype(proto_res->content().prototype());
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
const rapidjson::Value& child_root = children_root[i];
prefab child;
parse_prefab_inplace(
child,
parent_address,
child_root,
dependencies);
content.children().push_back(std::move(child));
}
}
if ( root.HasMember("mod_children") ) {
const rapidjson::Value& mod_children_root = root["mod_children"];
for ( rapidjson::SizeType i = 0; i < mod_children_root.Size(); ++i ) {
const rapidjson::Value& mod_child_root = mod_children_root[i];
E2D_ASSERT(
mod_child_root.HasMember("uuid") &&
mod_child_root["uuid"].IsString());
prefab* const child_prefab = find_prefab_child(
content,
mod_child_root["uuid"].GetString());
if ( !child_prefab ) {
the<debug>().error("PREFAB: Modifiable child is not found:\n"
"--> Child UUID: %0",
mod_child_root["uuid"].GetString());
throw prefab_asset_loading_exception();
}
parse_prefab_inplace(
*child_prefab,
parent_address,
mod_child_root,
dependencies);
}
}
if ( root.HasMember("components") ) {
@@ -154,30 +248,29 @@ namespace
str(parent_address),
component_root->value,
dependencies);
bool success = the<factory>().fill_prototype(
const bool success = the<factory>().fill_prototype(
component_root->name.GetString(),
content.prototype(),
ctx);
if ( !success ) {
throw prefab_asset_loading_exception();
}
}
}
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
vector<prefab> children;
children.reserve(children_root.Size());
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
children.emplace_back(parse_prefab(
parent_address, children_root[i], dependencies));
}
content.set_children(std::move(children));
}
prefab parse_prefab(
str_view parent_address,
const rapidjson::Value& root,
const asset_group& dependencies)
{
prefab content;
parse_prefab_inplace(
content,
parent_address,
root, dependencies);
return content;
}
}

View File

@@ -87,6 +87,12 @@ namespace e2d::bindings::high
return n.add_child(c);
},
"add_child_at", [](node& n, const node_iptr& c, i32 i) -> bool {
return i >= 0
? n.add_child_at(c, math::numeric_cast<std::size_t>(i))
: false;
},
"add_child_to_back", [](node& n, const node_iptr& c) -> bool {
return n.add_child_to_back(c);
},
@@ -115,6 +121,22 @@ namespace e2d::bindings::high
return n.remove_child(c);
},
"remove_child_at", [](node& n, i32 i) -> node_iptr {
return i >= 0
? n.remove_child_at(math::numeric_cast<std::size_t>(i))
: node_iptr();
},
"swap_children", [](node& n, const node_iptr& cl, const node_iptr& cr) -> bool {
return n.swap_children(cl, cr);
},
"swap_children_at", [](node& n, i32 cl, i32 cr) -> bool {
return cl >= 0 && cr >= 0
? n.swap_children_at(math::numeric_cast<std::size_t>(cl), math::numeric_cast<std::size_t>(cr))
: false;
},
"send_backward", [](node& n) -> bool {
return n.send_backward();
},
@@ -141,7 +163,17 @@ namespace e2d::bindings::high
[](node& n) -> node_iptr { return n.prev_sibling(); }),
"next_sibling", sol::property(
[](node& n) -> node_iptr { return n.next_sibling(); })
[](node& n) -> node_iptr { return n.next_sibling(); }),
"child_at", [](node& n, i32 i) -> node_iptr {
return i >= 0
? n.child_at(math::numeric_cast<std::size_t>(i))
: node_iptr();
},
"child_index", [](node& n, const node_iptr& c) -> std::pair<std::size_t, bool> {
return n.child_index(c);
}
);
}
}

View File

@@ -207,14 +207,25 @@ namespace e2d
return count;
}
bool node::add_child(const node_iptr& child) noexcept {
bool node::add_child(
const node_iptr& child) noexcept
{
return add_child_to_front(child);
}
bool node::add_child_at(
const node_iptr& child,
std::size_t index) noexcept
{
return index == 0u
? add_child_to_back(child)
: add_child_after(child_at(index - 1u), child);
}
bool node::add_child_to_back(
const node_iptr& child) noexcept
{
if ( !child ) {
if ( !child || child == this ) {
return false;
}
@@ -233,7 +244,7 @@ namespace e2d
bool node::add_child_to_front(
const node_iptr& child) noexcept
{
if ( !child ) {
if ( !child || child == this ) {
return false;
}
@@ -319,6 +330,41 @@ namespace e2d
return true;
}
node_iptr node::remove_child_at(std::size_t index) noexcept {
node_iptr child = child_at(index);
return remove_child(child)
? child
: node_iptr();
}
bool node::swap_children(
const node_iptr& child_l,
const node_iptr& child_r) noexcept
{
if ( !child_l || !child_r ) {
return false;
}
if ( child_l->parent_ != this || child_r->parent_ != this ) {
return false;
}
node_children::iterator_swap(
node_children::iterator_to(*child_l),
node_children::iterator_to(*child_r));
return true;
}
bool node::swap_children_at(
std::size_t child_l,
std::size_t child_r) noexcept
{
return swap_children(
child_at(child_l),
child_at(child_r));
}
bool node::send_backward() noexcept {
node_iptr prev = prev_sibling();
return prev
@@ -414,6 +460,36 @@ namespace e2d
}
return const_node_iptr(&*iter);
}
node_iptr node::child_at(std::size_t index) noexcept {
node_iptr child = first_child();
for ( std::size_t i = 0; i < index && child; ++i ) {
child = child->next_sibling();
}
return child;
}
const_node_iptr node::child_at(std::size_t index) const noexcept {
const_node_iptr child = first_child();
for ( std::size_t i = 0; i < index && child; ++i ) {
child = child->next_sibling();
}
return child;
}
std::pair<std::size_t, bool> node::child_index(
const const_node_iptr& child) const noexcept
{
if ( !child || child->parent_ != this ) {
return {std::size_t(-1), false};
}
const auto distance = std::distance(
children_.begin(),
node_children::iterator_to(*child));
return {math::numeric_cast<std::size_t>(distance), true};
}
}
namespace e2d

View File

@@ -25,14 +25,16 @@ namespace e2d
}
void prefab::clear() noexcept {
prototype_.clear();
uuid_.clear();
children_.clear();
prototype_.clear();
}
void prefab::swap(prefab& other) noexcept {
using std::swap;
swap(prototype_, other.prototype_);
swap(uuid_, other.uuid_);
swap(children_, other.children_);
swap(prototype_, other.prototype_);
}
prefab& prefab::assign(prefab&& other) noexcept {
@@ -46,20 +48,21 @@ namespace e2d
prefab& prefab::assign(const prefab& other) {
if ( this != &other ) {
prefab s;
s.prototype_ = other.prototype_;
s.uuid_ = other.uuid_;
s.children_ = other.children_;
s.prototype_ = other.prototype_;
swap(s);
}
return *this;
}
prefab& prefab::set_prototype(ecs::prototype&& proto) noexcept {
prototype_ = std::move(proto);
prefab& prefab::set_uuid(str&& uuid) noexcept {
uuid_ = std::move(uuid);
return *this;
}
prefab& prefab::set_prototype(const ecs::prototype& proto) {
prototype_ = proto;
prefab& prefab::set_uuid(const str& uuid) {
uuid_ = uuid;
return *this;
}
@@ -73,6 +76,32 @@ namespace e2d
return *this;
}
prefab& prefab::set_prototype(ecs::prototype&& prototype) noexcept {
prototype_ = std::move(prototype);
return *this;
}
prefab& prefab::set_prototype(const ecs::prototype& prototype) {
prototype_ = prototype;
return *this;
}
str& prefab::uuid() noexcept {
return uuid_;
}
const str& prefab::uuid() const noexcept {
return uuid_;
}
vector<prefab>& prefab::children() noexcept {
return children_;
}
const vector<prefab>& prefab::children() const noexcept {
return children_;
}
ecs::prototype& prefab::prototype() noexcept {
return prototype_;
}
@@ -80,10 +109,6 @@ namespace e2d
const ecs::prototype& prefab::prototype() const noexcept {
return prototype_;
}
const vector<prefab>& prefab::children() const noexcept {
return children_;
}
}
namespace e2d
@@ -91,13 +116,4 @@ namespace e2d
void swap(prefab& l, prefab& r) noexcept {
l.swap(r);
}
bool operator==(const prefab& l, const prefab& r) noexcept {
return l.prototype().empty() && l.children().empty()
&& r.prototype().empty() && r.children().empty();
}
bool operator!=(const prefab& l, const prefab& r) noexcept {
return !(l == r);
}
}

View File

@@ -197,6 +197,12 @@ namespace
}
}]
},
"guid" : {
"type" : "string",
"minLength" : 36,
"maxLength" : 36,
"pattern" : "^[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}$"
},
"name" : {
"type" : "string",
"minLength" : 1

View File

@@ -1,20 +0,0 @@
{
"components" : {
"touchable" : {},
"rect_collider" : {
"size" : [1,2],
"offset" : [2,4]
},
"circle_collider" : {
"radius" : 5,
"offset" : [4,2]
},
"polygon_collider" : {
"points" : [[1,2],[2,3],[3,4]],
"offset" : [8,4]
}
}
}

View File

@@ -0,0 +1,64 @@
{
"prefab" : "prefab_root.json",
"components" : {
"named" : {
"name" : "child"
},
"rect_collider" : {
"size" : [1,2],
"offset" : [2,4]
},
"polygon_collider" : {
"points" : [[1,2],[2,3],[3,4]],
"offset" : [8,4]
}
},
"children" : [{
"uuid" : "C07CDC21-8D1A-45E5-9321-AC7B6FADA847",
"components" : {
"named" : {
"name" : "child(3)"
}
}
}],
"mod_children" : [{
"uuid" : "4A93547E-4635-4C2F-9C59-3546E11B1722",
"components" : {
"widget" : {
"size" : [10,10]
}
},
"children" : [{
"uuid" : "EA1F7728-8061-495E-9E8A-280C5E2979B3",
"prefab" : "prefab_root.json",
"components" : {
"named" : {
"name" : "subchild(1)"
}
}
}]
}, {
"uuid" : "58063213-9FC1-457C-B773-B826BE1BE6D7",
"components" : {
"widget" : {
"size" : [20,20]
}
},
"children" : [{
"uuid" : "4DDDD08D-F7B9-4588-8597-3E38051AC433",
"prefab" : "prefab_root.json",
"components" : {
"named" : {
"name" : "subchild(2)"
}
}
}]
}, {
"uuid" : "C07CDC21-8D1A-45E5-9321-AC7B6FADA847",
"components" : {
"widget" : {
"size" : [30,30]
}
}
}]
}

View File

@@ -0,0 +1,27 @@
{
"uuid" : "73740BC4-CE9F-4A7F-A029-4AB65027A8AE",
"components" : {
"named" : {
"name" : "root"
},
"circle_collider" : {
"radius" : 5,
"offset" : [4,2]
}
},
"children" : [{
"uuid" : "4A93547E-4635-4C2F-9C59-3546E11B1722",
"components" : {
"named" : {
"name" : "child(1)"
}
}
}, {
"uuid" : "58063213-9FC1-457C-B773-B826BE1BE6D7",
"components" : {
"named" : {
"name" : "child(2)"
}
}
}]
}

View File

@@ -259,28 +259,6 @@ TEST_CASE("library"){
REQUIRE(model_res->content().mesh()->content().indices_submesh_count() == 1);
REQUIRE_FALSE(model_res->content().mesh()->content().indices(0).empty());
}
{
auto prefab_res = l.load_asset<prefab_asset>("prefab.json");
REQUIRE(prefab_res);
ecs::registry w;
ecs::entity e = w.create_entity(prefab_res->content().prototype());
REQUIRE(e.exists_component<touchable>());
REQUIRE(e.exists_component<rect_collider>());
REQUIRE(e.get_component<rect_collider>().size() == v2f(1.f,2.f));
REQUIRE(e.get_component<rect_collider>().offset() == v2f(2.f,4.f));
REQUIRE(e.exists_component<circle_collider>());
REQUIRE(math::approximately(e.get_component<circle_collider>().radius(), 5.f));
REQUIRE(e.get_component<circle_collider>().offset() == v2f(4.f,2.f));
REQUIRE(e.exists_component<polygon_collider>());
REQUIRE(e.get_component<polygon_collider>().points() == vector<v2f>{{1,2},{2,3},{3,4}});
REQUIRE(e.get_component<polygon_collider>().offset() == v2f(8.f,4.f));
}
}
}
{

View File

@@ -9,19 +9,6 @@ using namespace e2d;
namespace
{
class safe_starter_initializer final : private noncopyable {
public:
safe_starter_initializer() {
modules::initialize<starter>(0, nullptr,
starter::parameters(
engine::parameters("world_untests", "enduro2d")));
}
~safe_starter_initializer() noexcept {
modules::shutdown<starter>();
}
};
class fake_node final : public node {
protected:
fake_node() : node() {
@@ -61,7 +48,6 @@ namespace
}
TEST_CASE("node") {
safe_starter_initializer initializer;
SECTION("empty_node") {
auto n = node::create();
REQUIRE(n);
@@ -317,6 +303,33 @@ TEST_CASE("node") {
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("swap_children") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
auto p2 = node::create();
auto n4 = node::create(p2);
auto n5 = node::create();
REQUIRE_FALSE(p->swap_children(n1, node_iptr()));
REQUIRE_FALSE(p->swap_children(node_iptr(), n1));
REQUIRE_FALSE(p->swap_children(n1, p2));
REQUIRE_FALSE(p->swap_children(n1, n4));
REQUIRE_FALSE(p->swap_children(n1, n5));
REQUIRE(p->swap_children(n1, n1)); // n1 n2 n3
REQUIRE(p->swap_children(n1, n2)); // n2 n1 n3
REQUIRE(p->swap_children(n2, n3)); // n3 n1 n2
REQUIRE(p->swap_children(n2, n1)); // n3 n2 n1
REQUIRE(p->child_at(0u) == n3);
REQUIRE(p->child_at(1u) == n2);
REQUIRE(p->child_at(2u) == n1);
}
SECTION("send_forward/bring_to_front") {
{
auto p = node::create();
@@ -429,6 +442,142 @@ TEST_CASE("node") {
REQUIRE_FALSE(cn4->next_sibling());
}
}
SECTION("child_at") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(p->child_at(0) == n1);
REQUIRE(p->child_at(1) == n2);
REQUIRE(p->child_at(2) == n3);
REQUIRE_FALSE(p->child_at(3));
{
const_node_iptr cp = p;
REQUIRE(cp->child_at(0) == n1);
REQUIRE(cp->child_at(1) == n2);
REQUIRE(cp->child_at(2) == n3);
REQUIRE_FALSE(cp->child_at(3));
}
}
SECTION("child_index") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
auto p2 = node::create();
auto n4 = node::create(p2);
auto n5 = node::create();
REQUIRE(p->child_index(n1).second);
REQUIRE(p->child_index(n2).second);
REQUIRE(p->child_index(n3).second);
REQUIRE_FALSE(p->child_index(n4).second);
REQUIRE_FALSE(p->child_index(n5).second);
REQUIRE(p->child_index(n1).first == 0u);
REQUIRE(p->child_index(n2).first == 1u);
REQUIRE(p->child_index(n3).first == 2u);
{
const_node_iptr cp = p;
const_node_iptr cn1 = n1;
const_node_iptr cn2 = n2;
const_node_iptr cn3 = n3;
const_node_iptr cn4 = n4;
const_node_iptr cn5 = n5;
REQUIRE(cp->child_index(cn1).second);
REQUIRE(cp->child_index(cn2).second);
REQUIRE(cp->child_index(cn3).second);
REQUIRE_FALSE(cp->child_index(cn4).second);
REQUIRE_FALSE(cp->child_index(cn5).second);
REQUIRE(cp->child_index(cn1).first == 0u);
REQUIRE(cp->child_index(cn2).first == 1u);
REQUIRE(cp->child_index(cn3).first == 2u);
}
}
SECTION("remove_child_at") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE_FALSE(n1->remove_child_at(0));
REQUIRE(p->remove_child_at(1) == n2);
REQUIRE_FALSE(n2->has_parent());
REQUIRE(p->child_count() == 2u);
REQUIRE(p->remove_child_at(0) == n1);
REQUIRE_FALSE(n1->has_parent());
REQUIRE(p->child_count() == 1u);
REQUIRE(p->remove_child_at(0) == n3);
REQUIRE_FALSE(n3->has_parent());
REQUIRE(p->child_count() == 0u);
}
SECTION("swap_children_at") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE_FALSE(p->swap_children_at(0u, 3u));
REQUIRE_FALSE(p->swap_children_at(3u, 0u));
REQUIRE(p->swap_children_at(0, 0)); // n1 n2 n3
REQUIRE(p->swap_children_at(0, 1)); // n2 n1 n3
REQUIRE(p->swap_children_at(0, 2)); // n3 n1 n2
REQUIRE(p->swap_children_at(2, 1)); // n3 n2 n1
REQUIRE(p->child_at(0u) == n3);
REQUIRE(p->child_at(1u) == n2);
REQUIRE(p->child_at(2u) == n1);
}
SECTION("add_child_at") {
auto p = node::create();
auto n1 = node::create();
auto n2 = node::create();
auto n3 = node::create();
auto n4 = node::create();
REQUIRE_FALSE(p->add_child_at(p, 0u));
REQUIRE_FALSE(p->add_child_at(nullptr, 0u));
REQUIRE_FALSE(p->add_child_at(n1, 1u));
REQUIRE(p->add_child_at(n1, 0u)); // n1
REQUIRE(p->add_child_at(n2, 0u)); // n2 n1
REQUIRE(p->add_child_at(n3, 2u)); // n2 n1 n3
REQUIRE(p->add_child_at(n4, 2u)); // n2 n1 n4 n3
REQUIRE(p->child_at(0u) == n2);
REQUIRE(p->child_at(1u) == n1);
REQUIRE(p->child_at(2u) == n4);
REQUIRE(p->child_at(3u) == n3);
REQUIRE_FALSE(p->add_child_at(n1, 5u));
REQUIRE(p->add_child_at(n1, 4u)); // n2 n4 n3 n1
REQUIRE(p->add_child_at(n3, 0u)); // n3 n2 n4 n1
REQUIRE(p->add_child_at(n4, 1u)); // n3 n4 n2 n1
REQUIRE(p->add_child_at(n4, p->child_index(n4).first)); // n3 n4 n2 n1
REQUIRE(p->child_at(0u) == n3);
REQUIRE(p->child_at(1u) == n4);
REQUIRE(p->child_at(2u) == n2);
REQUIRE(p->child_at(3u) == n1);
}
SECTION("add_child_to_back/add_child_to_front") {
auto p = node::create();
auto n1 = node::create();
@@ -439,6 +588,7 @@ TEST_CASE("node") {
REQUIRE(p->add_child_to_back(n1));
REQUIRE(p->add_child_to_back(n2));
REQUIRE(p->add_child_to_back(n3)); // n3 n2 n1
REQUIRE_FALSE(p->add_child_to_back(p));
REQUIRE_FALSE(p->add_child_to_back(nullptr));
REQUIRE(n1->prev_sibling() == n2);
@@ -474,6 +624,7 @@ TEST_CASE("node") {
REQUIRE(p->add_child_to_front(n1));
REQUIRE(p->add_child_to_front(n2));
REQUIRE(p->add_child_to_front(n3)); // n1 n2 n3
REQUIRE_FALSE(p->add_child_to_front(p));
REQUIRE_FALSE(p->add_child_to_front(nullptr));
REQUIRE(n1->next_sibling() == n2);

View File

@@ -0,0 +1,194 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "_high.hpp"
using namespace e2d;
namespace
{
class safe_starter_initializer final : private noncopyable {
public:
safe_starter_initializer() {
modules::initialize<starter>(0, nullptr,
starter::parameters(
engine::parameters("prefab_untests", "enduro2d")));
}
~safe_starter_initializer() noexcept {
modules::shutdown<starter>();
}
};
}
TEST_CASE("prefab"){
safe_starter_initializer initializer;
library& l = the<library>();
{
auto prefab_root_res = l.load_asset<prefab_asset>("prefab_root.json");
REQUIRE(prefab_root_res);
const prefab& prefab_root = prefab_root_res->content();
REQUIRE(prefab_root.uuid() == "73740BC4-CE9F-4A7F-A029-4AB65027A8AE");
REQUIRE(prefab_root.children().size() == 2u);
REQUIRE(prefab_root.children()[0].uuid() == "4A93547E-4635-4C2F-9C59-3546E11B1722");
REQUIRE(prefab_root.children()[1].uuid() == "58063213-9FC1-457C-B773-B826BE1BE6D7");
auto go = the<world>().instantiate(prefab_root);
{
REQUIRE(go.component<named>());
REQUIRE(go.component<named>()->name() == "root");
REQUIRE(go.component<circle_collider>());
REQUIRE(go.component<circle_collider>()->radius() == Approx(5.f));
REQUIRE(go.component<circle_collider>()->offset() == v2f(4.f,2.f));
}
{
node_iptr go_node = go.component<actor>()
? go.component<actor>()->node()
: node_iptr();
REQUIRE(go_node);
REQUIRE(go_node->owner() == go);
REQUIRE(go_node->child_count() == 2u);
node_iptr child1 = go_node->child_at(0u);
node_iptr child2 = go_node->child_at(1u);
REQUIRE(child1);
REQUIRE(child2);
gobject child1_go = child1->owner();
gobject child2_go = child2->owner();
REQUIRE(child1_go);
REQUIRE(child2_go);
REQUIRE(child1_go.component<named>());
REQUIRE(child1_go.component<named>()->name() == "child(1)");
REQUIRE(child2_go.component<named>());
REQUIRE(child2_go.component<named>()->name() == "child(2)");
node_iptr child1_node = child1_go.component<actor>()
? child1_go.component<actor>()->node()
: node_iptr();
node_iptr child2_node = child2_go.component<actor>()
? child2_go.component<actor>()->node()
: node_iptr();
REQUIRE(child1_node);
REQUIRE(child1_node->owner() == child1_go);
REQUIRE(child1_node->child_count() == 0u);
REQUIRE(child2_node);
REQUIRE(child2_node->owner() == child2_go);
REQUIRE(child2_node->child_count() == 0u);
}
}
{
auto prefab_child_res = l.load_asset<prefab_asset>("prefab_child.json");
REQUIRE(prefab_child_res);
const prefab& prefab_child = prefab_child_res->content();
REQUIRE(prefab_child.uuid().empty());
REQUIRE(prefab_child.children().size() == 3u);
REQUIRE(prefab_child.children()[0].uuid() == "4A93547E-4635-4C2F-9C59-3546E11B1722");
REQUIRE(prefab_child.children()[1].uuid() == "58063213-9FC1-457C-B773-B826BE1BE6D7");
REQUIRE(prefab_child.children()[2].uuid() == "C07CDC21-8D1A-45E5-9321-AC7B6FADA847");
auto go = the<world>().instantiate(prefab_child);
{
REQUIRE(go.component<named>());
REQUIRE(go.component<named>()->name() == "child");
REQUIRE(go.component<rect_collider>());
REQUIRE(go.component<rect_collider>()->size() == v2f(1.f,2.f));
REQUIRE(go.component<rect_collider>()->offset() == v2f(2.f,4.f));
REQUIRE(go.component<circle_collider>());
REQUIRE(go.component<circle_collider>()->radius() == Approx(5.f));
REQUIRE(go.component<circle_collider>()->offset() == v2f(4.f,2.f));
REQUIRE(go.component<polygon_collider>());
REQUIRE(go.component<polygon_collider>()->points() == vector<v2f>{{1,2},{2,3},{3,4}});
REQUIRE(go.component<polygon_collider>()->offset() == v2f(8.f,4.f));
}
{
node_iptr go_node = go.component<actor>()
? go.component<actor>()->node()
: node_iptr();
REQUIRE(go_node);
REQUIRE(go_node->owner() == go);
REQUIRE(go_node->child_count() == 3u);
node_iptr child1 = go_node->child_at(0u);
node_iptr child2 = go_node->child_at(1u);
node_iptr child3 = go_node->child_at(2u);
REQUIRE(child1);
REQUIRE(child2);
REQUIRE(child3);
gobject child1_go = child1->owner();
gobject child2_go = child2->owner();
gobject child3_go = child3->owner();
REQUIRE(child1_go);
REQUIRE(child2_go);
REQUIRE(child3_go);
REQUIRE(child1_go.component<named>());
REQUIRE(child1_go.component<widget>());
REQUIRE(child1_go.component<named>()->name() == "child(1)");
REQUIRE(child1_go.component<widget>()->size() == v2f(10.f, 10.f));
REQUIRE(child2_go.component<named>());
REQUIRE(child2_go.component<widget>());
REQUIRE(child2_go.component<named>()->name() == "child(2)");
REQUIRE(child2_go.component<widget>()->size() == v2f(20.f, 20.f));
REQUIRE(child3_go.component<named>());
REQUIRE(child3_go.component<widget>());
REQUIRE(child3_go.component<named>()->name() == "child(3)");
REQUIRE(child3_go.component<widget>()->size() == v2f(30.f, 30.f));
node_iptr child1_node = child1_go.component<actor>()
? child1_go.component<actor>()->node()
: node_iptr();
node_iptr child2_node = child2_go.component<actor>()
? child2_go.component<actor>()->node()
: node_iptr();
node_iptr child3_node = child3_go.component<actor>()
? child3_go.component<actor>()->node()
: node_iptr();
REQUIRE(child1_node);
REQUIRE(child1_node->owner() == child1_go);
REQUIRE(child1_node->child_count() == 1u);
REQUIRE(child1_node->first_child()->child_count() == 2u);
REQUIRE(child2_node);
REQUIRE(child2_node->owner() == child2_go);
REQUIRE(child2_node->child_count() == 1u);
REQUIRE(child2_node->first_child()->child_count() == 2u);
REQUIRE(child3_node);
REQUIRE(child3_node->owner() == child3_go);
REQUIRE(child3_node->child_count() == 0u);
}
}
}

View File

@@ -7,6 +7,8 @@
#include "_utils.hpp"
using namespace e2d;
#include <random>
namespace
{
struct ilist_tag1 {};
@@ -21,6 +23,10 @@ namespace
obj_t() = default;
obj_t(int ni) : i(ni) {}
};
bool operator<(const obj_t& l, const obj_t& r) noexcept {
return l.i < r.i;
}
}
TEST_CASE("intrusive_list") {
@@ -433,4 +439,36 @@ TEST_CASE("intrusive_list") {
}
}
}
SECTION("sort") {
{
std::random_device rd;
std::mt19937 rnd(rd());
std::uniform_int_distribution<u32> uni_size(0, 1024);
std::uniform_int_distribution<i32> uni_number(-65536, 65535);
const auto pred = [](const obj_t& l, const obj_t& r) noexcept {
return l.i < r.i;
};
const auto r_pred = [](const obj_t& l, const obj_t& r) noexcept {
return l.i > r.i;
};
for ( std::size_t i = 0; i < 1024; ++i ) {
vector<std::unique_ptr<obj_t>> objs;
intrusive_list<obj_t, ilist_tag1> l;
for ( u32 b = 0, e = uni_size(rnd); b < e; ++b ) {
objs.push_back(std::make_unique<obj_t>(uni_number(rnd)));
l.push_back(*objs.back());
}
l.sort();
REQUIRE(std::is_sorted(l.cbegin(), l.cend()));
l.sort(r_pred);
REQUIRE(std::is_sorted(l.cbegin(), l.cend(), r_pred));
l.sort(pred);
REQUIRE(std::is_sorted(l.cbegin(), l.cend(), pred));
}
}
}
}