node hold children by reference counting

This commit is contained in:
2019-02-09 01:08:31 +07:00
parent 83ff7330b8
commit 69103badbf
13 changed files with 966 additions and 1037 deletions

View File

@@ -11,7 +11,6 @@
#include "components/camera.hpp"
#include "components/drawable.hpp"
#include "components/sprite.hpp"
#include "components/transform.hpp"
#include "scene/actor.hpp"
#include "scene/node.hpp"

View File

@@ -41,8 +41,6 @@ namespace e2d
class camera;
class drawable;
class sprite;
class transform2d;
class transform3d;
class actor;
class node;

View File

@@ -10,7 +10,7 @@
namespace e2d
{
class camera {
class camera final {
public:
camera() = default;

View File

@@ -11,7 +11,7 @@
namespace e2d
{
class drawable {
class drawable final {
public:
drawable();
drawable(const node_iptr& node);

View File

@@ -10,7 +10,7 @@
namespace e2d
{
class sprite {
class sprite final {
public:
sprite() = default;

View File

@@ -1,50 +0,0 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#pragma once
#include "../_high.hpp"
namespace e2d
{
class transform2d {
public:
transform2d() = default;
transform2d& position(const v2f& value) noexcept;
transform2d& rotation(f32 value) noexcept;
transform2d& scale(const v2f& value) noexcept;
const v2f& position() const noexcept;
f32 rotation() const noexcept;
const v2f& scale() const noexcept;
m4f as_matrix() const noexcept;
private:
v2f position_ = v2f::zero();
f32 rotation_ = 0.f;
v2f scale_ = v2f::unit();
};
class transform3d {
public:
transform3d() = default;
transform3d& position(const v3f& value) noexcept;
transform3d& rotation(const q4f& value) noexcept;
transform3d& scale(const v3f& value) noexcept;
const v3f& position() const noexcept;
const q4f& rotation() const noexcept;
const v3f& scale() const noexcept;
m4f as_matrix() const noexcept;
private:
v3f position_ = v3f::zero();
q4f rotation_ = q4f::identity();
v3f scale_ = v3f::unit();
};
}

View File

@@ -78,7 +78,7 @@ namespace e2d
class null_disposer {
public:
template < typename... Args >
void operator()(Args&&... args) noexcept {
void operator()(Args&&... args) const noexcept {
E2D_UNUSED(std::forward<Args>(args)...);
}
};

View File

@@ -1,84 +0,0 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#include <enduro2d/high/components/transform.hpp>
namespace e2d
{
//
// transform2d
//
transform2d& transform2d::position(const v2f& value) noexcept {
position_ = value;
return *this;
}
transform2d& transform2d::rotation(f32 value) noexcept {
rotation_ = value;
return *this;
}
transform2d& transform2d::scale(const v2f& value) noexcept {
scale_ = value;
return *this;
}
const v2f& transform2d::position() const noexcept {
return position_;
}
f32 transform2d::rotation() const noexcept {
return rotation_;
}
const v2f& transform2d::scale() const noexcept {
return scale_;
}
m4f transform2d::as_matrix() const noexcept {
return math::make_scale_matrix4(scale_)
* math::make_rotation_matrix4(make_rad(rotation_), v4f::unit_z())
* math::make_translation_matrix4(position_);
}
//
// transform3d
//
transform3d& transform3d::position(const v3f& value) noexcept {
position_ = value;
return *this;
}
transform3d& transform3d::rotation(const q4f& value) noexcept {
rotation_ = value;
return *this;
}
transform3d& transform3d::scale(const v3f& value) noexcept {
scale_ = value;
return *this;
}
const v3f& transform3d::position() const noexcept {
return position_;
}
const q4f& transform3d::rotation() const noexcept {
return rotation_;
}
const v3f& transform3d::scale() const noexcept {
return scale_;
}
m4f transform3d::as_matrix() const noexcept {
return math::make_scale_matrix4(scale_)
* math::make_rotation_matrix4(rotation_)
* math::make_translation_matrix4(position_);
}
}

View File

@@ -6,23 +6,29 @@
#include <enduro2d/high/scene/node.hpp>
namespace
{
using namespace e2d;
struct iptr_release_disposer {
void operator()(node* n) const noexcept {
intrusive_ptr_release(n);
}
};
}
namespace e2d
{
node::node() = default;
node::~node() noexcept {
E2D_ASSERT(!parent_);
while ( !children_.empty() ) {
node_iptr child(&children_.back());
children_.pop_back();
children_.pop_back_and_dispose(iptr_release_disposer());
child->parent_ = nullptr;
child->on_change_parent_();
}
if ( parent_ ) {
parent_->children_.erase(
node_children::iterator_to(*this));
parent_->on_change_children_();
parent_ = nullptr;
}
}
node_iptr node::create() {
@@ -130,8 +136,10 @@ namespace e2d
if ( !parent_ ) {
return false;
}
parent_->children_.erase(
node_children::iterator_to(*this));
node_iptr self(this);
parent_->children_.erase_and_dispose(
node_children::iterator_to(*this),
iptr_release_disposer());
parent_->on_change_children_();
parent_ = nullptr;
on_change_parent_();
@@ -142,7 +150,7 @@ namespace e2d
std::size_t count = 0;
while ( !children_.empty() ) {
node_iptr child(&children_.back());
children_.pop_back();
children_.pop_back_and_dispose(iptr_release_disposer());
child->parent_ = nullptr;
child->on_change_parent_();
++count;
@@ -188,11 +196,14 @@ namespace e2d
}
if ( child->parent_ ) {
child->parent_->children_.erase(node_children::iterator_to(*child));
child->parent_->children_.erase_and_dispose(
node_children::iterator_to(*child),
iptr_release_disposer());
child->parent_->on_change_children_();
child->parent_ = nullptr;
}
intrusive_ptr_add_ref(child.get());
children_.push_front(*child);
child->parent_ = this;
child->on_change_parent_();
@@ -219,11 +230,14 @@ namespace e2d
}
if ( child->parent_ ) {
child->parent_->children_.erase(node_children::iterator_to(*child));
child->parent_->children_.erase_and_dispose(
node_children::iterator_to(*child),
iptr_release_disposer());
child->parent_->on_change_children_();
child->parent_ = nullptr;
}
intrusive_ptr_add_ref(child.get());
children_.push_back(*child);
child->parent_ = this;
child->on_change_parent_();
@@ -253,11 +267,14 @@ namespace e2d
}
if ( child->parent_ ) {
child->parent_->children_.erase(node_children::iterator_to(*child));
child->parent_->children_.erase_and_dispose(
node_children::iterator_to(*child),
iptr_release_disposer());
child->parent_->on_change_children_();
child->parent_ = nullptr;
}
intrusive_ptr_add_ref(child.get());
children_.insert(
node_children::iterator_to(*before),
*child);
@@ -289,11 +306,14 @@ namespace e2d
}
if ( child->parent_ ) {
child->parent_->children_.erase(node_children::iterator_to(*child));
child->parent_->children_.erase_and_dispose(
node_children::iterator_to(*child),
iptr_release_disposer());
child->parent_->on_change_children_();
child->parent_ = nullptr;
}
intrusive_ptr_add_ref(child.get());
children_.insert(
++node_children::iterator_to(*after),
*child);

View File

@@ -0,0 +1,11 @@
/*******************************************************************************
* 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 "_high.hpp"
using namespace e2d;
TEST_CASE("actor") {
}

View File

@@ -0,0 +1,917 @@
/*******************************************************************************
* 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 "_high.hpp"
using namespace e2d;
namespace
{
class fake_node final : public node {
protected:
fake_node() {
++s_ctor_count;
}
~fake_node() noexcept final {
++s_dtor_count;
}
void on_change_parent_() noexcept override {
++parent_changes;
++s_parent_changes;
}
void on_change_children_() noexcept override {
++children_changes;
++s_children_changes;
}
public:
static void reset_counters() noexcept {
s_ctor_count = 0;
s_dtor_count = 0;
s_parent_changes = 0;
s_children_changes = 0;
}
std::size_t parent_changes{0};
std::size_t children_changes{0};
static std::size_t s_ctor_count;
static std::size_t s_dtor_count;
static std::size_t s_parent_changes;
static std::size_t s_children_changes;
public:
static intrusive_ptr<fake_node> create() {
return intrusive_ptr<fake_node>(new fake_node());
}
static intrusive_ptr<fake_node> create(const node_iptr& parent) {
auto child = create();
if ( parent ) {
parent->add_child(child);
}
return child;
}
};
std::size_t fake_node::s_ctor_count{0};
std::size_t fake_node::s_dtor_count{0};
std::size_t fake_node::s_parent_changes{0};
std::size_t fake_node::s_children_changes{0};
}
TEST_CASE("node") {
SECTION("empty_node") {
auto n = node::create();
REQUIRE(n);
REQUIRE(n->root() == n);
REQUIRE_FALSE(n->parent());
REQUIRE(n->child_count() == 0);
REQUIRE_FALSE(n->prev_sibling());
REQUIRE_FALSE(n->next_sibling());
{
const_node_iptr cn = n;
REQUIRE(cn);
REQUIRE(cn->root() == cn);
REQUIRE_FALSE(cn->parent());
REQUIRE(cn->child_count() == 0);
REQUIRE_FALSE(cn->prev_sibling());
REQUIRE_FALSE(cn->next_sibling());
}
}
SECTION("parent/root") {
{
auto p = node::create();
auto n = node::create();
REQUIRE(p->add_child(n));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
REQUIRE(p->add_child(n));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
REQUIRE_FALSE(p->add_child(nullptr));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
}
{
auto p = node::create();
auto n1 = node::create(p);
REQUIRE(n1->parent() == p);
REQUIRE(p->child_count() == 1);
auto n2 = node::create(nullptr);
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 1);
}
{
auto p1 = node::create();
auto p2 = node::create();
auto n = node::create(p1);
REQUIRE(n->parent() == p1);
REQUIRE(p1->child_count() == 1);
REQUIRE(p2->child_count() == 0);
REQUIRE(p2->add_child(n));
REQUIRE(n->parent() == p2);
REQUIRE(p1->child_count() == 0);
REQUIRE(p2->child_count() == 1);
}
{
auto p1 = node::create();
auto p2 = node::create(p1);
auto n1 = node::create(p1);
auto n2 = node::create(p2);
REQUIRE(n1->parent() == p1);
REQUIRE(n2->parent() == p2);
REQUIRE(n1->root() == p1);
REQUIRE(n2->root() == p1);
auto n3 = node::create();
REQUIRE_FALSE(n3->parent());
REQUIRE(n3->root() == n3);
{
const_node_iptr cn1 = n1;
const_node_iptr cn2 = n2;
REQUIRE(cn1->parent() == p1);
REQUIRE(cn2->parent() == p2);
REQUIRE(cn1->root() == p1);
REQUIRE(cn2->root() == p1);
const_node_iptr cn3 = node::create();
REQUIRE_FALSE(cn3->parent());
REQUIRE(cn3->root() == cn3);
}
}
}
SECTION("has_parent") {
auto p = node::create();
REQUIRE_FALSE(p->has_parent());
REQUIRE_FALSE(p->has_parent(nullptr));
auto n = node::create(p);
REQUIRE(n->has_parent());
REQUIRE(n->has_parent(p));
REQUIRE(n->has_parent(nullptr));
auto pp = node::create();
REQUIRE_FALSE(n->has_parent(pp));
REQUIRE_FALSE(pp->has_parent(pp));
pp->add_child(p);
REQUIRE(n->has_parent(p));
REQUIRE(n->has_parent(pp));
REQUIRE_FALSE(n->has_parent(n));
REQUIRE_FALSE(pp->has_parent(pp));
}
SECTION("auto_remove/remove_all_children") {
{
auto p = node::create();
auto n = node::create(p);
n->remove_from_parent();
REQUIRE(p->child_count() == 0);
}
{
auto p = node::create();
auto n = node::create(p);
p.reset();
REQUIRE_FALSE(n->parent());
}
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
REQUIRE(p->child_count() == 2);
REQUIRE(p->remove_all_children() == 2);
REQUIRE_FALSE(n1->parent());
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 0);
REQUIRE(p->remove_all_children() == 0);
}
}
SECTION("auto_remove/remove_all_children/events") {
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n = fake_node::create(p);
n->remove_from_parent();
REQUIRE(p->children_changes == 2);
REQUIRE(fake_node::s_parent_changes == 2);
}
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n = fake_node::create(p);
p.reset();
REQUIRE(fake_node::s_children_changes == 1);
REQUIRE(n->parent_changes == 2);
}
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
REQUIRE(p->remove_all_children() == 2);
REQUIRE(p->remove_all_children() == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(fake_node::s_parent_changes == 4);
}
}
SECTION("remove_from_parent") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto np = node::create();
np->remove_from_parent();
REQUIRE(np->root() == np);
REQUIRE_FALSE(np->parent());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p);
REQUIRE(n1->remove_from_parent());
REQUIRE_FALSE(n1->parent());
REQUIRE(p->child_count() == 1);
REQUIRE(n2->remove_from_parent());
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 0);
}
SECTION("remove_from_parent/events") {
fake_node::reset_counters();
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto np = fake_node::create();
np->remove_from_parent();
REQUIRE(fake_node::s_parent_changes == 2);
REQUIRE(fake_node::s_children_changes == 2);
REQUIRE(n1->remove_from_parent());
REQUIRE(fake_node::s_parent_changes == 3);
REQUIRE(fake_node::s_children_changes == 3);
REQUIRE(n2->remove_from_parent());
REQUIRE(fake_node::s_parent_changes == 4);
REQUIRE(fake_node::s_children_changes == 4);
}
SECTION("child_count/child_count_recursive") {
auto p1 = node::create();
REQUIRE(p1->child_count() == 0);
REQUIRE(p1->child_count_recursive() == 0);
auto p2 = node::create(p1);
REQUIRE(p1->child_count() == 1);
REQUIRE(p1->child_count_recursive() == 1);
REQUIRE(p2->child_count() == 0);
REQUIRE(p2->child_count_recursive() == 0);
auto n1 = node::create(p2);
auto n2 = node::create(p2);
REQUIRE(p1->child_count() == 1);
REQUIRE(p1->child_count_recursive() == 3);
REQUIRE(p2->child_count() == 2);
REQUIRE(p2->child_count_recursive() == 2);
}
SECTION("send_backward/bring_to_back") {
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(n3->send_backward()); // n1 n3 n2
REQUIRE(n1->next_sibling() == n3);
REQUIRE(n3->send_backward()); // n3 n1 n2
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n3->send_backward()); // n3 n1 n2
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
}
{
auto n = node::create();
REQUIRE_FALSE(n->send_backward());
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("send_backward/bring_to_back/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto n3 = fake_node::create(p);
REQUIRE(n3->send_backward()); // n1 n3 n2
REQUIRE(n3->send_backward()); // n3 n1 n2
REQUIRE_FALSE(n3->send_backward()); // n3 n1 n2
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(p->children_changes == 6);
}
{
auto n = fake_node::create();
REQUIRE_FALSE(n->send_backward());
REQUIRE_FALSE(n->bring_to_back());
REQUIRE(n->children_changes == 0);
}
}
SECTION("send_forward/bring_to_front") {
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(n1->send_forward()); // n2 n1 n3
REQUIRE(n2->next_sibling() == n1);
REQUIRE(n1->send_forward()); // n2 n3 n1
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->send_forward()); // n2 n3 n1
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n1->next_sibling() == n2);
}
{
auto n = node::create();
REQUIRE_FALSE(n->send_forward());
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("send_forward/bring_to_front/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto n3 = fake_node::create(p);
REQUIRE(n1->send_forward()); // n2 n1 n3
REQUIRE(n1->send_forward()); // n2 n3 n1
REQUIRE_FALSE(n1->send_forward()); // n2 n3 n1
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(p->children_changes == 6);
}
{
auto n = fake_node::create();
REQUIRE_FALSE(n->send_forward());
REQUIRE_FALSE(n->bring_to_back());
REQUIRE(n->children_changes == 0);
}
}
SECTION("last_child/first_child") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(p->last_child() == n3);
REQUIRE(p->first_child() == n1);
{
const_node_iptr cp = p;
REQUIRE(cp->last_child() == n3);
REQUIRE(cp->first_child() == n1);
}
}
SECTION("prev_sibling/next_sibling") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->prev_sibling() == n1);
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->prev_sibling() == n2);
REQUIRE_FALSE(n3->next_sibling());
auto n4 = node::create();
REQUIRE_FALSE(n4->prev_sibling());
REQUIRE_FALSE(n4->next_sibling());
{
const_node_iptr cn1 = n1;
const_node_iptr cn2 = n2;
const_node_iptr cn3 = n3;
REQUIRE_FALSE(cn1->prev_sibling());
REQUIRE(cn1->next_sibling() == cn2);
REQUIRE(cn2->prev_sibling() == cn1);
REQUIRE(cn2->next_sibling() == cn3);
REQUIRE(cn3->prev_sibling() == cn2);
REQUIRE_FALSE(cn3->next_sibling());
const_node_iptr cn4 = n4;
REQUIRE_FALSE(cn4->prev_sibling());
REQUIRE_FALSE(cn4->next_sibling());
}
}
SECTION("add_child_to_back/add_child_to_front") {
auto p = node::create();
auto n1 = node::create();
auto n2 = node::create();
auto n3 = node::create();
{
p->remove_all_children();
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(nullptr));
REQUIRE(n1->prev_sibling() == n2);
REQUIRE(n2->prev_sibling() == n3);
REQUIRE_FALSE(n3->prev_sibling());
// add to self parent (change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(n2->prev_sibling() == n3);
REQUIRE(n3->prev_sibling() == n1);
REQUIRE_FALSE(n1->prev_sibling());
// add to self parent (no change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(n2->prev_sibling() == n3);
REQUIRE(n3->prev_sibling() == n1);
REQUIRE_FALSE(n1->prev_sibling());
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_back(n1));
REQUIRE(n1->parent() == p2);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p2);
REQUIRE(n2->parent() == p);
REQUIRE(n3->parent() == p);
}
{
p->remove_all_children();
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(nullptr));
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n3);
REQUIRE_FALSE(n3->next_sibling());
// add to self parent (change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->next_sibling());
// add to self parent (no change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->next_sibling());
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_front(n1));
REQUIRE(n1->parent() == p2);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p2);
REQUIRE(n2->parent() == p);
REQUIRE(n3->parent() == p);
}
}
SECTION("add_child_to_back/add_child_to_front/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
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(nullptr));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (no change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_back(n1));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
REQUIRE(n1->parent_changes == 2);
REQUIRE(n1->children_changes == 0);
REQUIRE(n2->parent_changes == 1);
REQUIRE(n2->children_changes == 0);
}
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
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(nullptr));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (no change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_front(n1));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
REQUIRE(n1->parent_changes == 2);
REQUIRE(n1->children_changes == 0);
REQUIRE(n2->parent_changes == 1);
REQUIRE(n2->children_changes == 0);
}
}
SECTION("add_child_after/add_child_before") {
auto p = node::create();
auto n1 = node::create();
auto n2 = node::create();
auto n3 = node::create();
{
p->remove_all_children();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(n1->add_sibling_before(n2)); // n2 n1
REQUIRE(n1->add_sibling_before(n3)); // n2 n3 n1
REQUIRE(n1->add_sibling_before(n1)); // n2 n3 n1
REQUIRE(n3->add_sibling_before(n2)); // n2 n3 n1
REQUIRE_FALSE(n1->add_sibling_before(nullptr));
REQUIRE_FALSE(p->add_child_before(nullptr, n1));
REQUIRE_FALSE(p->add_child_before(nullptr, nullptr));
REQUIRE_FALSE(p->add_sibling_before(n3));
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n3->add_sibling_before(n1)); // n2 n1 n3
REQUIRE(n2->add_sibling_before(n3)); // n3 n2 n1
REQUIRE(n3->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n1);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(n4->add_sibling_before(n2)); // n2 n4
REQUIRE(n2->parent() == p2);
REQUIRE_FALSE(n2->prev_sibling());
REQUIRE(n2->next_sibling() == n4);
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p2);
REQUIRE(n3->parent() == p);
}
{
p->remove_all_children();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(n1->add_sibling_after(n2)); // n1 n2
REQUIRE(n1->add_sibling_after(n3)); // n1 n3 n2
REQUIRE(n1->add_sibling_after(n1)); // n1 n3 n2
REQUIRE(n3->add_sibling_after(n2)); // n1 n3 n2
REQUIRE_FALSE(n1->add_sibling_after(nullptr));
REQUIRE_FALSE(p->add_child_after(nullptr, n1));
REQUIRE_FALSE(p->add_child_after(nullptr, nullptr));
REQUIRE_FALSE(p->add_sibling_after(n3));
REQUIRE(n1->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n2);
REQUIRE(n3->add_sibling_after(n1)); // n3 n1 n2
REQUIRE(n2->add_sibling_after(n3)); // n1 n2 n3
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n3);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(n4->add_sibling_after(n2)); // n4 n2
REQUIRE(n2->parent() == p2);
REQUIRE(n2->prev_sibling() == n4);
REQUIRE_FALSE(n2->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p2);
REQUIRE(n3->parent() == p);
}
}
SECTION("add_child_after/add_child_before/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(p->add_child_before(n1, n2)); // n2 n1
REQUIRE(p->add_child_before(n1, n3)); // n2 n3 n1
REQUIRE(p->add_child_before(n1, n1)); // n2 n3 n1
REQUIRE(p->add_child_before(n3, n2)); // n2 n3 n1
REQUIRE_FALSE(p->add_child_before(n1, nullptr));
REQUIRE_FALSE(p->add_child_before(nullptr, n1));
REQUIRE_FALSE(p->add_child_before(nullptr, nullptr));
REQUIRE_FALSE(p->add_child_before(p, n3));
REQUIRE(p->add_child_before(n3, n1)); // n2 n1 n3
REQUIRE(p->add_child_before(n2, n3)); // n3 n2 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(p2->add_child_before(n4, n2)); // n2 n4
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 6);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n2->parent_changes == 2);
}
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(p->add_child_after(n1, n2)); // n1 n2
REQUIRE(p->add_child_after(n1, n3)); // n1 n3 n2
REQUIRE(p->add_child_after(n1, n1)); // n1 n3 n2
REQUIRE(p->add_child_after(n3, n2)); // n1 n3 n2
REQUIRE_FALSE(p->add_child_after(n1, nullptr));
REQUIRE_FALSE(p->add_child_after(nullptr, n1));
REQUIRE_FALSE(p->add_child_after(nullptr, nullptr));
REQUIRE_FALSE(p->add_child_after(p, n3));
REQUIRE(p->add_child_after(n3, n1)); // n3 n1 n2
REQUIRE(p->add_child_after(n2, n3)); // n1 n2 n3
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(p2->add_child_after(n4, n2)); // n4 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 6);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n2->parent_changes == 2);
}
}
SECTION("for_each_child") {
auto p = node::create();
array<node_iptr, 3> ns{
node::create(p),
node::create(p),
node::create(p)};
{
std::size_t count = 0;
p->for_each_child([&ns, &count](const node_iptr& n){
REQUIRE(ns[count++] == n);
});
REQUIRE(count == 3);
}
{
const_node_iptr cp = p;
std::size_t count = 0;
cp->for_each_child([&ns, &count](const const_node_iptr& n){
REQUIRE(ns[count++] == n);
});
REQUIRE(count == 3);
}
}
SECTION("destroy_node") {
auto p1 = node::create();
auto p2 = node::create(p1);
auto n1 = node::create(p2);
auto n2 = node::create(p2);
p2->remove_from_parent();
p2.reset();
REQUIRE(p1->child_count() == 0);
REQUIRE(p1->child_count_recursive() == 0);
REQUIRE(n1->root() == n1);
REQUIRE_FALSE(n1->parent());
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(n2->root() == n2);
REQUIRE_FALSE(n2->parent());
REQUIRE_FALSE(n2->prev_sibling());
REQUIRE_FALSE(n2->next_sibling());
}
SECTION("destroy_node/events") {
fake_node::reset_counters();
auto p1 = fake_node::create();
auto p2 = fake_node::create(p1);
auto n1 = fake_node::create(p2);
auto n2 = fake_node::create(p2);
REQUIRE(fake_node::s_parent_changes == 3);
REQUIRE(fake_node::s_children_changes == 3);
p2->remove_from_parent();
p2.reset();
REQUIRE(fake_node::s_parent_changes == 6);
REQUIRE(fake_node::s_children_changes == 4);
}
SECTION("local_matrix") {
{
auto p = node::create();
p->transform(math::make_translation_trs3(v3f{10.f,0.f,0.f}));
auto n = node::create(p);
n->transform(math::make_translation_trs3(v3f{20.f,0.f,0.f}));
REQUIRE(n->local_matrix() == math::make_translation_matrix4(20.f,0.f,0.f));
auto v = v4f(5.f,0.f,0.f,1.f);
REQUIRE(v * n->local_matrix() == v4f{25.f,0.f,0.f,1.f});
n->transform(math::make_scale_trs3(v3f(1.f,2.f,3.f)));
REQUIRE(n->local_matrix() == math::make_scale_matrix4(1.f,2.f,3.f));
}
}
SECTION("world_matrix") {
{
auto p = node::create();
p->translation({10.f,0.f,0.f});
auto n = node::create(p);
n->translation({20.f,0.f,0.f});
auto v = v4f(5.f,0.f,0.f,1.f);
REQUIRE(v * n->world_matrix() == v4f{35.f,0.f,0.f,1.f});
n->transform(math::make_scale_trs3(v3f(1.f,2.f,3.f)));
REQUIRE(n->world_matrix() ==
math::make_scale_matrix4(1.f,2.f,3.f) *
math::make_translation_matrix4(10.f,0.f,0.f));
}
{
auto n = node::create();
n->translation({20.f,0.f,0.f});
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(20.f,0.f,0.f));
auto p = node::create();
p->transform(math::make_translation_trs3(v3f{10.f,0.f,0.f}));
p->add_child(n);
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(30.f,0.f,0.f));
}
{
auto p1 = node::create();
p1->translation({10.f,0.f,0.f});
auto p2 = node::create();
p2->transform(math::make_translation_trs3(v3f{20.f,0.f,0.f}));
auto n = node::create(p2);
n->transform(math::make_translation_trs3(v3f{30.f,0.f,0.f}));
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(50.f,0.f,0.f));
p1->add_child(p2);
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(60.f,0.f,0.f));
}
}
SECTION("lifetime") {
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n = fake_node::create();
p->add_child(n);
REQUIRE(fake_node::s_ctor_count == 2);
REQUIRE(fake_node::s_dtor_count == 0);
n.reset();
REQUIRE(fake_node::s_ctor_count == 2);
REQUIRE(fake_node::s_dtor_count == 0);
REQUIRE(p->child_count() == 1);
p.reset();
REQUIRE(fake_node::s_ctor_count == 2);
REQUIRE(fake_node::s_dtor_count == 2);
}
{
fake_node::reset_counters();
auto p = fake_node::create();
{
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
}
REQUIRE(fake_node::s_ctor_count == 3);
REQUIRE(fake_node::s_dtor_count == 0);
p->remove_all_children();
REQUIRE(fake_node::s_ctor_count == 3);
REQUIRE(fake_node::s_dtor_count == 2);
}
}
}

View File

@@ -7,868 +7,5 @@
#include "_high.hpp"
using namespace e2d;
namespace
{
class fake_node : public node {
public:
void on_change_parent_() noexcept override {
++parent_changes;
++s_parent_changes;
}
void on_change_children_() noexcept override {
++children_changes;
++s_children_changes;
}
public:
static void reset_counters() noexcept {
s_parent_changes = 0;
s_children_changes = 0;
}
std::size_t parent_changes{0};
std::size_t children_changes{0};
static std::size_t s_parent_changes;
static std::size_t s_children_changes;
public:
static intrusive_ptr<fake_node> create() {
return intrusive_ptr<fake_node>(new fake_node());
}
static intrusive_ptr<fake_node> create(const node_iptr& parent) {
auto child = create();
if ( parent ) {
parent->add_child(child);
}
return child;
}
};
std::size_t fake_node::s_parent_changes{0};
std::size_t fake_node::s_children_changes{0};
}
TEST_CASE("scene") {
auto s = scene::create();
REQUIRE(s);
REQUIRE(s->root());
}
TEST_CASE("node") {
SECTION("empty_node") {
auto n = node::create();
REQUIRE(n);
REQUIRE(n->root() == n);
REQUIRE_FALSE(n->parent());
REQUIRE(n->child_count() == 0);
REQUIRE_FALSE(n->prev_sibling());
REQUIRE_FALSE(n->next_sibling());
{
const_node_iptr cn = n;
REQUIRE(cn);
REQUIRE(cn->root() == cn);
REQUIRE_FALSE(cn->parent());
REQUIRE(cn->child_count() == 0);
REQUIRE_FALSE(cn->prev_sibling());
REQUIRE_FALSE(cn->next_sibling());
}
}
SECTION("parent/root") {
{
auto p = node::create();
auto n = node::create();
REQUIRE(p->add_child(n));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
REQUIRE(p->add_child(n));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
REQUIRE_FALSE(p->add_child(nullptr));
REQUIRE(n->parent() == p);
REQUIRE(p->child_count() == 1);
}
{
auto p = node::create();
auto n1 = node::create(p);
REQUIRE(n1->parent() == p);
REQUIRE(p->child_count() == 1);
auto n2 = node::create(nullptr);
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 1);
}
{
auto p1 = node::create();
auto p2 = node::create();
auto n = node::create(p1);
REQUIRE(n->parent() == p1);
REQUIRE(p1->child_count() == 1);
REQUIRE(p2->child_count() == 0);
REQUIRE(p2->add_child(n));
REQUIRE(n->parent() == p2);
REQUIRE(p1->child_count() == 0);
REQUIRE(p2->child_count() == 1);
}
{
auto p1 = node::create();
auto p2 = node::create(p1);
auto n1 = node::create(p1);
auto n2 = node::create(p2);
REQUIRE(n1->parent() == p1);
REQUIRE(n2->parent() == p2);
REQUIRE(n1->root() == p1);
REQUIRE(n2->root() == p1);
auto n3 = node::create();
REQUIRE_FALSE(n3->parent());
REQUIRE(n3->root() == n3);
{
const_node_iptr cn1 = n1;
const_node_iptr cn2 = n2;
REQUIRE(cn1->parent() == p1);
REQUIRE(cn2->parent() == p2);
REQUIRE(cn1->root() == p1);
REQUIRE(cn2->root() == p1);
const_node_iptr cn3 = node::create();
REQUIRE_FALSE(cn3->parent());
REQUIRE(cn3->root() == cn3);
}
}
}
SECTION("has_parent") {
auto p = node::create();
REQUIRE_FALSE(p->has_parent());
REQUIRE_FALSE(p->has_parent(nullptr));
auto n = node::create(p);
REQUIRE(n->has_parent());
REQUIRE(n->has_parent(p));
REQUIRE(n->has_parent(nullptr));
auto pp = node::create();
REQUIRE_FALSE(n->has_parent(pp));
REQUIRE_FALSE(pp->has_parent(pp));
pp->add_child(p);
REQUIRE(n->has_parent(p));
REQUIRE(n->has_parent(pp));
REQUIRE_FALSE(n->has_parent(n));
REQUIRE_FALSE(pp->has_parent(pp));
}
SECTION("auto_remove/remove_all_children") {
{
auto p = node::create();
auto n = node::create(p);
n.reset();
REQUIRE(p->child_count() == 0);
}
{
auto p = node::create();
auto n = node::create(p);
p.reset();
REQUIRE_FALSE(n->parent());
}
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
REQUIRE(p->child_count() == 2);
REQUIRE(p->remove_all_children() == 2);
REQUIRE_FALSE(n1->parent());
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 0);
REQUIRE(p->remove_all_children() == 0);
}
}
SECTION("auto_remove/remove_all_children/events") {
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n = fake_node::create(p);
n.reset();
REQUIRE(p->children_changes == 2);
REQUIRE(fake_node::s_parent_changes == 1);
}
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n = fake_node::create(p);
p.reset();
REQUIRE(fake_node::s_children_changes == 1);
REQUIRE(n->parent_changes == 2);
}
{
fake_node::reset_counters();
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
REQUIRE(p->remove_all_children() == 2);
REQUIRE(p->remove_all_children() == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(fake_node::s_parent_changes == 4);
}
}
SECTION("remove_from_parent") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto np = node::create();
np->remove_from_parent();
REQUIRE(np->root() == np);
REQUIRE_FALSE(np->parent());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p);
REQUIRE(n1->remove_from_parent());
REQUIRE_FALSE(n1->parent());
REQUIRE(p->child_count() == 1);
REQUIRE(n2->remove_from_parent());
REQUIRE_FALSE(n2->parent());
REQUIRE(p->child_count() == 0);
}
SECTION("remove_from_parent/events") {
fake_node::reset_counters();
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto np = fake_node::create();
np->remove_from_parent();
REQUIRE(fake_node::s_parent_changes == 2);
REQUIRE(fake_node::s_children_changes == 2);
REQUIRE(n1->remove_from_parent());
REQUIRE(fake_node::s_parent_changes == 3);
REQUIRE(fake_node::s_children_changes == 3);
REQUIRE(n2->remove_from_parent());
REQUIRE(fake_node::s_parent_changes == 4);
REQUIRE(fake_node::s_children_changes == 4);
}
SECTION("child_count/child_count_recursive") {
auto p1 = node::create();
REQUIRE(p1->child_count() == 0);
REQUIRE(p1->child_count_recursive() == 0);
auto p2 = node::create(p1);
REQUIRE(p1->child_count() == 1);
REQUIRE(p1->child_count_recursive() == 1);
REQUIRE(p2->child_count() == 0);
REQUIRE(p2->child_count_recursive() == 0);
auto n1 = node::create(p2);
auto n2 = node::create(p2);
REQUIRE(p1->child_count() == 1);
REQUIRE(p1->child_count_recursive() == 3);
REQUIRE(p2->child_count() == 2);
REQUIRE(p2->child_count_recursive() == 2);
}
SECTION("send_backward/bring_to_back") {
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(n3->send_backward()); // n1 n3 n2
REQUIRE(n1->next_sibling() == n3);
REQUIRE(n3->send_backward()); // n3 n1 n2
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n3->send_backward()); // n3 n1 n2
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
}
{
auto n = node::create();
REQUIRE_FALSE(n->send_backward());
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("send_backward/bring_to_back/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto n3 = fake_node::create(p);
REQUIRE(n3->send_backward()); // n1 n3 n2
REQUIRE(n3->send_backward()); // n3 n1 n2
REQUIRE_FALSE(n3->send_backward()); // n3 n1 n2
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(n2->bring_to_back()); // n2 n3 n1
REQUIRE(p->children_changes == 6);
}
{
auto n = fake_node::create();
REQUIRE_FALSE(n->send_backward());
REQUIRE_FALSE(n->bring_to_back());
REQUIRE(n->children_changes == 0);
}
}
SECTION("send_forward/bring_to_front") {
{
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(n1->send_forward()); // n2 n1 n3
REQUIRE(n2->next_sibling() == n1);
REQUIRE(n1->send_forward()); // n2 n3 n1
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->send_forward()); // n2 n3 n1
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n1->next_sibling() == n2);
}
{
auto n = node::create();
REQUIRE_FALSE(n->send_forward());
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("send_forward/bring_to_front/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create(p);
auto n2 = fake_node::create(p);
auto n3 = fake_node::create(p);
REQUIRE(n1->send_forward()); // n2 n1 n3
REQUIRE(n1->send_forward()); // n2 n3 n1
REQUIRE_FALSE(n1->send_forward()); // n2 n3 n1
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(n2->bring_to_front()); // n3 n1 n2
REQUIRE(p->children_changes == 6);
}
{
auto n = fake_node::create();
REQUIRE_FALSE(n->send_forward());
REQUIRE_FALSE(n->bring_to_back());
REQUIRE(n->children_changes == 0);
}
}
SECTION("last_child/first_child") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE(p->last_child() == n3);
REQUIRE(p->first_child() == n1);
{
const_node_iptr cp = p;
REQUIRE(cp->last_child() == n3);
REQUIRE(cp->first_child() == n1);
}
}
SECTION("prev_sibling/next_sibling") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->prev_sibling() == n1);
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->prev_sibling() == n2);
REQUIRE_FALSE(n3->next_sibling());
auto n4 = node::create();
REQUIRE_FALSE(n4->prev_sibling());
REQUIRE_FALSE(n4->next_sibling());
{
const_node_iptr cn1 = n1;
const_node_iptr cn2 = n2;
const_node_iptr cn3 = n3;
REQUIRE_FALSE(cn1->prev_sibling());
REQUIRE(cn1->next_sibling() == cn2);
REQUIRE(cn2->prev_sibling() == cn1);
REQUIRE(cn2->next_sibling() == cn3);
REQUIRE(cn3->prev_sibling() == cn2);
REQUIRE_FALSE(cn3->next_sibling());
const_node_iptr cn4 = n4;
REQUIRE_FALSE(cn4->prev_sibling());
REQUIRE_FALSE(cn4->next_sibling());
}
}
SECTION("add_child_to_back/add_child_to_front") {
auto p = node::create();
auto n1 = node::create();
auto n2 = node::create();
auto n3 = node::create();
{
p->remove_all_children();
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(nullptr));
REQUIRE(n1->prev_sibling() == n2);
REQUIRE(n2->prev_sibling() == n3);
REQUIRE_FALSE(n3->prev_sibling());
// add to self parent (change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(n2->prev_sibling() == n3);
REQUIRE(n3->prev_sibling() == n1);
REQUIRE_FALSE(n1->prev_sibling());
// add to self parent (no change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(n2->prev_sibling() == n3);
REQUIRE(n3->prev_sibling() == n1);
REQUIRE_FALSE(n1->prev_sibling());
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_back(n1));
REQUIRE(n1->parent() == p2);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p2);
REQUIRE(n2->parent() == p);
REQUIRE(n3->parent() == p);
}
{
p->remove_all_children();
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(nullptr));
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n3);
REQUIRE_FALSE(n3->next_sibling());
// add to self parent (change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->next_sibling());
// add to self parent (no change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE_FALSE(n1->next_sibling());
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_front(n1));
REQUIRE(n1->parent() == p2);
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p2);
REQUIRE(n2->parent() == p);
REQUIRE(n3->parent() == p);
}
}
SECTION("add_child_to_back/add_child_to_front/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
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(nullptr));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (no change order)
REQUIRE(p->add_child_to_back(n1)); // n1 n3 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_back(n1));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
REQUIRE(n1->parent_changes == 2);
REQUIRE(n1->children_changes == 0);
REQUIRE(n2->parent_changes == 1);
REQUIRE(n2->children_changes == 0);
}
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
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(nullptr));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 3);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to self parent (no change order)
REQUIRE(p->add_child_to_front(n1)); // n2 n3 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 4);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n1->children_changes == 0);
// add to another parent
auto p2 = node::create();
REQUIRE(p2->add_child_to_front(n1));
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
REQUIRE(n1->parent_changes == 2);
REQUIRE(n1->children_changes == 0);
REQUIRE(n2->parent_changes == 1);
REQUIRE(n2->children_changes == 0);
}
}
SECTION("add_child_after/add_child_before") {
auto p = node::create();
auto n1 = node::create();
auto n2 = node::create();
auto n3 = node::create();
{
p->remove_all_children();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(n1->add_sibling_before(n2)); // n2 n1
REQUIRE(n1->add_sibling_before(n3)); // n2 n3 n1
REQUIRE(n1->add_sibling_before(n1)); // n2 n3 n1
REQUIRE(n3->add_sibling_before(n2)); // n2 n3 n1
REQUIRE_FALSE(n1->add_sibling_before(nullptr));
REQUIRE_FALSE(p->add_child_before(nullptr, n1));
REQUIRE_FALSE(p->add_child_before(nullptr, nullptr));
REQUIRE_FALSE(p->add_sibling_before(n3));
REQUIRE(n2->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n1);
REQUIRE(n3->add_sibling_before(n1)); // n2 n1 n3
REQUIRE(n2->add_sibling_before(n3)); // n3 n2 n1
REQUIRE(n3->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n1);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(n4->add_sibling_before(n2)); // n2 n4
REQUIRE(n2->parent() == p2);
REQUIRE_FALSE(n2->prev_sibling());
REQUIRE(n2->next_sibling() == n4);
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p2);
REQUIRE(n3->parent() == p);
}
{
p->remove_all_children();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(n1->add_sibling_after(n2)); // n1 n2
REQUIRE(n1->add_sibling_after(n3)); // n1 n3 n2
REQUIRE(n1->add_sibling_after(n1)); // n1 n3 n2
REQUIRE(n3->add_sibling_after(n2)); // n1 n3 n2
REQUIRE_FALSE(n1->add_sibling_after(nullptr));
REQUIRE_FALSE(p->add_child_after(nullptr, n1));
REQUIRE_FALSE(p->add_child_after(nullptr, nullptr));
REQUIRE_FALSE(p->add_sibling_after(n3));
REQUIRE(n1->next_sibling() == n3);
REQUIRE(n3->next_sibling() == n2);
REQUIRE(n3->add_sibling_after(n1)); // n3 n1 n2
REQUIRE(n2->add_sibling_after(n3)); // n1 n2 n3
REQUIRE(n1->next_sibling() == n2);
REQUIRE(n2->next_sibling() == n3);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(n4->add_sibling_after(n2)); // n4 n2
REQUIRE(n2->parent() == p2);
REQUIRE(n2->prev_sibling() == n4);
REQUIRE_FALSE(n2->next_sibling());
REQUIRE(p->child_count() == 2);
REQUIRE(n1->parent() == p);
REQUIRE(n2->parent() == p2);
REQUIRE(n3->parent() == p);
}
}
SECTION("add_child_after/add_child_before/events") {
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(p->add_child_before(n1, n2)); // n2 n1
REQUIRE(p->add_child_before(n1, n3)); // n2 n3 n1
REQUIRE(p->add_child_before(n1, n1)); // n2 n3 n1
REQUIRE(p->add_child_before(n3, n2)); // n2 n3 n1
REQUIRE_FALSE(p->add_child_before(n1, nullptr));
REQUIRE_FALSE(p->add_child_before(nullptr, n1));
REQUIRE_FALSE(p->add_child_before(nullptr, nullptr));
REQUIRE_FALSE(p->add_child_before(p, n3));
REQUIRE(p->add_child_before(n3, n1)); // n2 n1 n3
REQUIRE(p->add_child_before(n2, n3)); // n3 n2 n1
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(p2->add_child_before(n4, n2)); // n2 n4
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 6);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n2->parent_changes == 2);
}
{
auto p = fake_node::create();
auto n1 = fake_node::create();
auto n2 = fake_node::create();
auto n3 = fake_node::create();
REQUIRE(p->add_child(n1)); // n1
REQUIRE(p->add_child_after(n1, n2)); // n1 n2
REQUIRE(p->add_child_after(n1, n3)); // n1 n3 n2
REQUIRE(p->add_child_after(n1, n1)); // n1 n3 n2
REQUIRE(p->add_child_after(n3, n2)); // n1 n3 n2
REQUIRE_FALSE(p->add_child_after(n1, nullptr));
REQUIRE_FALSE(p->add_child_after(nullptr, n1));
REQUIRE_FALSE(p->add_child_after(nullptr, nullptr));
REQUIRE_FALSE(p->add_child_after(p, n3));
REQUIRE(p->add_child_after(n3, n1)); // n3 n1 n2
REQUIRE(p->add_child_after(n2, n3)); // n1 n2 n3
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 5);
// to another parent
auto p2 = node::create();
auto n4 = node::create(p2); // n4
REQUIRE(p2->add_child_after(n4, n2)); // n4 n2
REQUIRE(p->parent_changes == 0);
REQUIRE(p->children_changes == 6);
REQUIRE(n1->parent_changes == 1);
REQUIRE(n2->parent_changes == 2);
}
}
SECTION("for_each_child") {
auto p = node::create();
array<node_iptr, 3> ns{
node::create(p),
node::create(p),
node::create(p)};
{
std::size_t count = 0;
p->for_each_child([&ns, &count](const node_iptr& n){
REQUIRE(ns[count++] == n);
});
REQUIRE(count == 3);
}
{
const_node_iptr cp = p;
std::size_t count = 0;
cp->for_each_child([&ns, &count](const const_node_iptr& n){
REQUIRE(ns[count++] == n);
});
REQUIRE(count == 3);
}
}
SECTION("destroy_node") {
auto p1 = node::create();
auto p2 = node::create(p1);
auto n1 = node::create(p2);
auto n2 = node::create(p2);
p2.reset();
REQUIRE(p1->child_count() == 0);
REQUIRE(p1->child_count_recursive() == 0);
REQUIRE(n1->root() == n1);
REQUIRE_FALSE(n1->parent());
REQUIRE_FALSE(n1->prev_sibling());
REQUIRE_FALSE(n1->next_sibling());
REQUIRE(n2->root() == n2);
REQUIRE_FALSE(n2->parent());
REQUIRE_FALSE(n2->prev_sibling());
REQUIRE_FALSE(n2->next_sibling());
}
SECTION("destroy_node/events") {
fake_node::reset_counters();
auto p1 = fake_node::create();
auto p2 = fake_node::create(p1);
auto n1 = fake_node::create(p2);
auto n2 = fake_node::create(p2);
REQUIRE(fake_node::s_parent_changes == 3);
REQUIRE(fake_node::s_children_changes == 3);
p2.reset();
REQUIRE(fake_node::s_parent_changes == 5);
REQUIRE(fake_node::s_children_changes == 4);
}
SECTION("local_matrix") {
{
auto p = node::create();
p->transform(math::make_translation_trs3(v3f{10.f,0.f,0.f}));
auto n = node::create(p);
n->transform(math::make_translation_trs3(v3f{20.f,0.f,0.f}));
REQUIRE(n->local_matrix() == math::make_translation_matrix4(20.f,0.f,0.f));
auto v = v4f(5.f,0.f,0.f,1.f);
REQUIRE(v * n->local_matrix() == v4f{25.f,0.f,0.f,1.f});
n->transform(math::make_scale_trs3(v3f(1.f,2.f,3.f)));
REQUIRE(n->local_matrix() == math::make_scale_matrix4(1.f,2.f,3.f));
}
}
SECTION("world_matrix") {
{
auto p = node::create();
p->translation({10.f,0.f,0.f});
auto n = node::create(p);
n->translation({20.f,0.f,0.f});
auto v = v4f(5.f,0.f,0.f,1.f);
REQUIRE(v * n->world_matrix() == v4f{35.f,0.f,0.f,1.f});
n->transform(math::make_scale_trs3(v3f(1.f,2.f,3.f)));
REQUIRE(n->world_matrix() ==
math::make_scale_matrix4(1.f,2.f,3.f) *
math::make_translation_matrix4(10.f,0.f,0.f));
}
{
auto n = node::create();
n->translation({20.f,0.f,0.f});
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(20.f,0.f,0.f));
auto p = node::create();
p->transform(math::make_translation_trs3(v3f{10.f,0.f,0.f}));
p->add_child(n);
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(30.f,0.f,0.f));
}
{
auto p1 = node::create();
p1->translation({10.f,0.f,0.f});
auto p2 = node::create();
p2->transform(math::make_translation_trs3(v3f{20.f,0.f,0.f}));
auto n = node::create(p2);
n->transform(math::make_translation_trs3(v3f{30.f,0.f,0.f}));
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(50.f,0.f,0.f));
p1->add_child(p2);
REQUIRE(n->world_matrix() ==
math::make_translation_matrix4(60.f,0.f,0.f));
}
}
}

View File

@@ -28,23 +28,4 @@ TEST_CASE("world"){
safe_starter_initializer initializer;
world& w = the<world>();
REQUIRE(w.scene());
SECTION("actor/drawable"){
auto parent_e = w.registry().create_entity();
auto actor_e = w.registry().create_entity();
{
REQUIRE(parent_e.assign_component<drawable>());
node_iptr parent_n = parent_e.get_component<drawable>().node();
w.scene()->root()->add_child(parent_n);
actor_iptr actor_n = actor::create(actor_e);
REQUIRE(actor_e.assign_component<drawable>(actor_n));
parent_n->add_child(actor_n);
}
REQUIRE(w.scene()->root()->child_count_recursive() == 2);
w.registry().destroy_entity(parent_e);
REQUIRE(w.scene()->root()->child_count_recursive() == 0);
REQUIRE(actor_e.get_component<drawable>().node());
REQUIRE_FALSE(actor_e.get_component<drawable>().node()->parent());
}
}