node: local and world transforms

This commit is contained in:
2019-02-08 06:30:47 +07:00
parent 1ce03f493d
commit e6352edfba
7 changed files with 168 additions and 26 deletions

View File

@@ -18,6 +18,24 @@ namespace e2d
}
}
namespace e2d
{
class node;
using node_iptr = intrusive_ptr<node>;
using const_node_iptr = intrusive_ptr<const node>;
class scene;
using scene_iptr = intrusive_ptr<scene>;
using const_scene_iptr = intrusive_ptr<const scene>;
class actor;
using actor_iptr = intrusive_ptr<actor>;
using const_actor_iptr = intrusive_ptr<const actor>;
class node_children_ilist_tag {};
using node_children = intrusive_list<node, node_children_ilist_tag>;
}
namespace e2d
{
class camera;

View File

@@ -9,13 +9,6 @@
#include "../_high.hpp"
#include "node.hpp"
namespace e2d
{
class actor;
using actor_iptr = intrusive_ptr<actor>;
using const_actor_iptr = intrusive_ptr<const actor>;
}
namespace e2d
{
class actor final : public node {

View File

@@ -10,16 +10,6 @@
#include "../_high.hpp"
namespace e2d
{
class node;
using node_iptr = intrusive_ptr<node>;
using const_node_iptr = intrusive_ptr<const node>;
class node_children_ilist_tag {};
using node_children = intrusive_list<node, node_children_ilist_tag>;
}
namespace e2d
{
class node
@@ -32,6 +22,20 @@ namespace e2d
static node_iptr create();
static node_iptr create(const node_iptr& parent);
//
// transform
//
void transform(const t3f& transform) noexcept;
const t3f& transform() const noexcept;
const m4f& local_matrix() const noexcept;
const m4f& world_matrix() const noexcept;
//
// container
//
node_iptr root() noexcept;
const_node_iptr root() const noexcept;
@@ -99,8 +103,22 @@ namespace e2d
virtual void on_change_parent_() noexcept;
virtual void on_change_children_() noexcept;
private:
enum flag_masks : u32 {
fm_dirty_local_matrix = 1u << 0,
fm_dirty_world_matrix = 1u << 1,
};
void mark_dirty_local_matrix_() noexcept;
void mark_dirty_world_matrix_() noexcept;
void update_local_matrix_() const noexcept;
void update_world_matrix_() const noexcept;
private:
t3f transform_;
node* parent_{nullptr};
node_children children_;
private:
mutable u32 flags_{0u};
mutable m4f local_matrix_;
mutable m4f world_matrix_;
};
}

View File

@@ -9,13 +9,6 @@
#include "../_high.hpp"
#include "node.hpp"
namespace e2d
{
class scene;
using scene_iptr = intrusive_ptr<scene>;
using const_scene_iptr = intrusive_ptr<const scene>;
}
namespace e2d
{
class scene
@@ -25,7 +18,8 @@ namespace e2d
virtual ~scene() noexcept;
static scene_iptr create();
const node_iptr& root() const noexcept;
node_iptr root() noexcept;
const_node_iptr root() const noexcept;
protected:
scene();
private:

View File

@@ -37,6 +37,29 @@ namespace e2d
return child;
}
void node::transform(const t3f& transform) noexcept {
transform_ = transform;
mark_dirty_local_matrix_();
}
const t3f& node::transform() const noexcept {
return transform_;
}
const m4f& node::local_matrix() const noexcept {
if ( math::check_and_clear_all_flags(flags_, fm_dirty_local_matrix) ) {
update_local_matrix_();
}
return local_matrix_;
}
const m4f& node::world_matrix() const noexcept {
if ( math::check_and_clear_all_flags(flags_, fm_dirty_world_matrix) ) {
update_world_matrix_();
}
return world_matrix_;
}
node_iptr node::root() noexcept {
node* n = this;
while ( n->parent_ ) {
@@ -368,8 +391,36 @@ namespace e2d
namespace e2d
{
void node::on_change_parent_() noexcept {
mark_dirty_world_matrix_();
}
void node::on_change_children_() noexcept {
}
}
namespace e2d
{
void node::mark_dirty_local_matrix_() noexcept {
if ( math::check_and_set_any_flags(flags_, fm_dirty_local_matrix) ) {
mark_dirty_world_matrix_();
}
}
void node::mark_dirty_world_matrix_() noexcept {
if ( math::check_and_set_any_flags(flags_, fm_dirty_world_matrix) ) {
for ( node& child : children_ ) {
child.mark_dirty_world_matrix_();
}
}
}
void node::update_local_matrix_() const noexcept {
local_matrix_ = math::make_trs_matrix4(transform_);
}
void node::update_world_matrix_() const noexcept {
world_matrix_ = parent_
? parent_->world_matrix() * local_matrix()
: local_matrix();
}
}

View File

@@ -15,7 +15,11 @@ namespace e2d
return scene_iptr(new scene());
}
const node_iptr& scene::root() const noexcept {
node_iptr scene::root() noexcept {
return root_;
}
const_node_iptr scene::root() const noexcept {
return root_;
}
}

View File

@@ -803,4 +803,68 @@ TEST_CASE("node") {
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->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}));
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->transform(math::make_translation_trs3(v3f{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->transform(math::make_translation_trs3(v3f{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));
}
}
}