Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 87 lines (71 sloc) 3.208 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
// Honeycomb, Copyright (C) 2014 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
#pragma once

#include "Honey/Scene/Com/Tree.h"
#include "Honey/Math/Alge/Transform.h"
#include "Honey/Misc/Lazy.h"

namespace honey
{

/// Transform component
/**
* Not all objects in the scene graph require a transform component.
* Objects without a tm component are skipped in the world tm calculations.
*/
class Tm : public SceneComponent, public Transform
{
public:
    COMPONENT(Tm)

    SIGNAL_DECL(Tm)
    /// Called on shape change
    SIGNAL(sigTmChange, (Tm& src));

    Tm() :
        _parent(nullptr),
        _world(bind_fill(&Tm::worldEval, this), bind(&Tm::worldDirty, this)),
        _worldState(1),
        _worldStateParent(0) {}

    Tm& operator=(const Transform& tm) { Transform::operator=(tm); return *this; }

    /// Get world transform. Also updates and caches this node's world tm, same as updateWorld().
    /**
* There are two ways to call world():
* \hiddentable
* \row Ancestors not updated (slower): \col Node will recursively check that parent world tms are up-to-date all the way to the root. \endrow
* \row Ancestors updated (faster): \col Ancestors are assumed to be up-to-date, no recursive check is necessary. \n
* This method can be used during a preorder traversal if world(true) is called on every node. \endrow
* \endtable
*/
    const Transform& world(bool ancestorsUpdated = false) const { const_cast<Tm*>(this)->updateWorld(ancestorsUpdated); return _world.raw(); }

    /// Get state counter that is incremented every time tm world changes
    int worldState() const { return _worldState; }

    /// Update world tm of this node. If updateTree is true then entire tree of descendants will also be updated.
    void updateWorld(bool ancestorsUpdated = false, bool updateTree = false);

private:
    static ComRegistry::DepNode createTypeDep() { ComRegistry::DepNode node; node.add(Tree::s_comType()); return node; }

    virtual void onComInsert()
    {
        obj().com<Tree>().listeners().add(Listener::create<Tree::sigSetParent>(bind(
            [&](Tree::Node* parent)
            {
                /// Get the nearest ancestor that has a tm component (usually the immediate parent)
                for (; parent && !(*parent)->hasCom<Tm>(); parent = (*parent)->com<Tree>().getParent());
                _parent = parent ? **parent : nullptr;
                _world.setDirty(true);
            }
            , _2), this));
    }

    virtual void onComRemove()
    {
        obj().com<Tree>().listeners().remove(this);
    }

    virtual void onTmChange()
    {
        _world.setDirty(true);
        listeners().dispatch<sigTmChange>(*this);
    }

    bool worldDirty();
    void worldEval(Transform& world);

    SceneObject* _parent;
    lazy<Transform> _world;
    atomic::Var<int> _worldState;
    atomic::Var<int> _worldStateParent;
};
COMPONENT_REG(Tm)

}
Something went wrong with that request. Please try again.