| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818 |
- /*
- * Node.cpp
- */
- #include "Base.h"
- #include "Node.h"
- #include "Scene.h"
- #define NODE_DIRTY_WORLD 1
- #define NODE_DIRTY_BOUNDS 2
- #define NODE_DIRTY_ALL (NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS)
- namespace gameplay
- {
- Node::Node(const char* id)
- : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(NULL),
- _camera(NULL), _light(NULL), _model(NULL), _audioSource(NULL), _particleEmitter(NULL), _physicsRigidBody(NULL),
- _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _boundsType(NONE)
- {
- if (id)
- {
- _id = id;
- }
- memset(&_bounds, 0, sizeof(_bounds));
- }
- Node::Node(const Node& node)
- {
- // hidden
- }
- Node::~Node()
- {
- removeAllChildren();
- // Free bounding volume.
- switch (_boundsType)
- {
- case BOX:
- SAFE_DELETE(_bounds.box);
- break;
- case SPHERE:
- SAFE_DELETE(_bounds.sphere);
- break;
- }
- SAFE_RELEASE(_camera);
- SAFE_RELEASE(_light);
- SAFE_RELEASE(_model);
- SAFE_RELEASE(_audioSource);
- SAFE_RELEASE(_particleEmitter);
- SAFE_DELETE(_physicsRigidBody);
- }
- Node* Node::create(const char* id)
- {
- return new Node(id);
- }
- const char* Node::getId() const
- {
- return _id.c_str();
- }
- void Node::setId(const char* id)
- {
- if (id)
- {
- _id = id;
- }
- }
- Node::Type Node::getType() const
- {
- return Node::NODE;
- }
- void Node::addChild(Node* child)
- {
- assert(child);
- if (child->_parent == this)
- {
- // This node is already present in our hierarchy
- return;
- }
- child->addRef();
- // If the item belongs to another hierarchy, remove it first.
- if (child->_parent)
- {
- child->_parent->removeChild(child);
- }
- else if (child->_scene)
- {
- child->_scene->removeNode(child);
- }
- // Order is irrelevant, so add to the beginning of the list.
- if (_firstChild)
- {
- _firstChild->_prevSibling = child;
- child->_nextSibling = _firstChild;
- _firstChild = child;
- }
- else
- {
- _firstChild = child;
- }
- child->_parent = this;
- ++_childCount;
- if (_notifyHierarchyChanged)
- {
- hierarchyChanged();
- }
- }
- void Node::removeChild(Node* child)
- {
- if (child == NULL || child->_parent != this)
- {
- // The child is not in our hierarchy.
- return;
- }
- // Call remove on the child.
- child->remove();
- SAFE_RELEASE(child);
- }
- void Node::removeAllChildren()
- {
- _notifyHierarchyChanged = false;
- while (_firstChild)
- {
- removeChild(_firstChild);
- }
- _notifyHierarchyChanged = true;
- hierarchyChanged();
- }
- void Node::remove()
- {
- // Re-link our neighbours.
- if (_prevSibling)
- {
- _prevSibling->_nextSibling = _nextSibling;
- }
- if (_nextSibling)
- {
- _nextSibling->_prevSibling = _prevSibling;
- }
- // Update our parent.
- Node* parent = _parent;
- if (parent)
- {
- if (this == parent->_firstChild)
- {
- parent->_firstChild = _nextSibling;
- }
- --parent->_childCount;
- }
- _nextSibling = NULL;
- _prevSibling = NULL;
- _parent = NULL;
- if (parent && parent->_notifyHierarchyChanged)
- {
- parent->hierarchyChanged();
- }
- }
- Node* Node::getFirstChild() const
- {
- return _firstChild;
- }
- Node* Node::getNextSibling() const
- {
- return _nextSibling;
- }
- Node* Node::getPreviousSibling() const
- {
- return _prevSibling;
- }
- Node* Node::getParent() const
- {
- return _parent;
- }
- unsigned int Node::getChildCount() const
- {
- return _childCount;
- }
- Node* Node::findNode(const char* id, bool recursive, bool exactMatch)
- {
- assert(id);
-
- // Search immediate children first.
- for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
- {
- // Does this child's ID match?
- if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
- {
- return child;
- }
- }
- // Recurse.
- if (recursive)
- {
- for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
- {
- Node* match = child->findNode(id, true, exactMatch);
- if (match)
- {
- return match;
- }
- }
- }
- return NULL;
- }
- unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch)
- {
- assert(id);
-
- unsigned int count = 0;
- // Search immediate children first.
- for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
- {
- // Does this child's ID match?
- if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
- {
- nodes.push_back(child);
- ++count;
- }
- }
- // Recurse.
- if (recursive)
- {
- for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
- {
- count += child->findNodes(id, nodes, true, exactMatch);
- }
- }
- return count;
- }
- Scene* Node::getScene() const
- {
- // Search for a scene in our parents.
- for (Node* n = const_cast<Node*>(this); n != NULL; n = n->getParent())
- {
- if (n->_scene)
- {
- return n->_scene;
- }
- }
- return NULL;
- }
- Node* Node::getRootNode() const
- {
- Node* n = const_cast<Node*>(this);
- while (n->getParent())
- {
- n = n->getParent();
- }
- return n;
- }
- const Matrix& Node::getWorldMatrix() const
- {
- if (_dirtyBits & NODE_DIRTY_WORLD)
- {
- // Clear our dirty flag immediately to prevent this block from being entered if our
- // parent calls our getWorldMatrix() method as a result of the following calculations.
- _dirtyBits &= ~NODE_DIRTY_WORLD;
- // If we have a parent, multiply our parent world transform by our local
- // transform to obtain our final resolved world transform.
- Node* parent = getParent();
- if (parent && !_physicsRigidBody)
- {
- Matrix::multiply(parent->getWorldMatrix(), getMatrix(), &_world);
- }
- else
- {
- _world = getMatrix();
- }
- // Our world matrix was just updated, so call getWorldMatrix() on all child nodes
- // to force their resolved world matrices to be updated.
- Node* node = getFirstChild();
- while (node)
- {
- node->getWorldMatrix();
- node = node->getNextSibling();
- }
- }
- return _world;
- }
- const Matrix& Node::getWorldViewMatrix() const
- {
- static Matrix worldView;
-
- Matrix::multiply(getViewMatrix(), getWorldMatrix(), &worldView);
- return worldView;
- }
- const Matrix& Node::getInverseTransposeWorldViewMatrix() const
- {
- static Matrix invTransWorldView;
- // Assume the matrix is always dirty since the camera is moving
- // almost every frame in most games.
- //
- // TODO: Optimize here to NOT calculate the inverse transpose if the matrix is orthogonal.
- Matrix::multiply(getViewMatrix(), getWorldMatrix(), &invTransWorldView);
- invTransWorldView.invert();
- invTransWorldView.transpose();
- return invTransWorldView;
- }
- const Matrix& Node::getViewMatrix() const
- {
- Scene* scene = getScene();
- Camera* camera = scene ? scene->getActiveCamera() : NULL;
- if (camera)
- {
- return camera->getViewMatrix();
- }
- else
- {
- return Matrix::identity();
- }
- }
- const Matrix& Node::getInverseViewMatrix() const
- {
- Scene* scene = getScene();
- Camera* camera = scene ? scene->getActiveCamera() : NULL;
- if (camera)
- {
- return camera->getInverseViewMatrix();
- }
- else
- {
- return Matrix::identity();
- }
- }
- const Matrix& Node::getViewProjectionMatrix() const
- {
- Scene* scene = getScene();
- Camera* camera = scene ? scene->getActiveCamera() : NULL;
- if (camera)
- {
- return camera->getViewProjectionMatrix();
- }
- else
- {
- return Matrix::identity();
- }
- }
- const Matrix& Node::getInverseViewProjectionMatrix() const
- {
- Scene* scene = getScene();
- Camera* camera = scene ? scene->getActiveCamera() : NULL;
- if (camera)
- {
- return camera->getInverseViewProjectionMatrix();
- }
- return Matrix::identity();
- }
- const Matrix& Node::getWorldViewProjectionMatrix() const
- {
- static Matrix worldViewProj;
- // Always re-calculate worldViewProjection matrix since it's extremely difficult
- // to track whether the camera has changed (it may frequently change every frame).
- Matrix::multiply(getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
- return worldViewProj;
- }
- Vector3 Node::getTranslationWorld() const
- {
- Vector3 translation;
- getWorldMatrix().getTranslation(&translation);
- return translation;
- }
- Vector3 Node::getTranslationView() const
- {
- Vector3 translation;
- getWorldMatrix().getTranslation(&translation);
- getViewMatrix().transformPoint(&translation);
- return translation;
- }
- Vector3 Node::getForwardVectorWorld() const
- {
- Vector3 vector;
- getWorldMatrix().getForwardVector(&vector);
- return vector;
- }
- Vector3 Node::getForwardVectorView() const
- {
- Vector3 vector;
- getWorldMatrix().getForwardVector(&vector);
- getViewMatrix().transformVector(&vector);
- return vector;
- }
- Vector3 Node::getActiveCameraTranslationWorld() const
- {
- Scene* scene = getScene();
- if (scene)
- {
- Camera* camera = scene->getActiveCamera();
- if (camera)
- {
- Node* cameraNode = camera->getNode();
- if (cameraNode)
- {
- return cameraNode->getTranslationWorld();
- }
- }
- }
- return Vector3::zero();
- }
- void Node::hierarchyChanged()
- {
- // When our hierarchy changes our world transform is affected, so we must dirty it.
- transformChanged();
- }
- void Node::transformChanged()
- {
- // Our local transform was changed, so mark our world matrices dirty.
- _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
- // Notify our children that their transform has also changed (since transforms are inherited).
- Node* n = getFirstChild();
- while (n)
- {
- n->transformChanged();
- n = n->getNextSibling();
- }
- Transform::transformChanged();
- }
- Camera* Node::getCamera() const
- {
- return _camera;
- }
- void Node::setCamera(Camera* camera)
- {
- if (_camera != camera)
- {
- if (_camera)
- {
- _camera->setNode(NULL);
- SAFE_RELEASE(_camera);
- }
- _camera = camera;
- if (_camera)
- {
- _camera->addRef();
- _camera->setNode(this);
- }
- }
- }
- Light* Node::getLight() const
- {
- return _light;
- }
- void Node::setLight(Light* light)
- {
- if (_light != light)
- {
- if (_light)
- {
- _light->setNode(NULL);
- SAFE_RELEASE(_light);
- }
-
- _light = light;
- if (_light)
- {
- _light->addRef();
- _light->setNode(this);
- }
- }
- }
- void Node::setModel(Model* model)
- {
- if (_model != model)
- {
- if (_model)
- {
- _model->setNode(NULL);
- SAFE_RELEASE(_model);
- }
- _model = model;
- if (_model)
- {
- _model->addRef();
- _model->setNode(this);
- }
- }
- }
- Model* Node::getModel() const
- {
- return _model;
- }
- const BoundingBox& Node::getBoundingBox() const
- {
- if (_boundsType != BOX)
- {
- return BoundingBox::empty();
- }
- if (_dirtyBits & NODE_DIRTY_BOUNDS)
- {
- _dirtyBits &= ~NODE_DIRTY_BOUNDS;
- if (_model && _model->getMesh())
- {
- // Use the bounding volume of our model's mesh.
- Mesh* mesh = _model->getMesh();
- _bounds.box->set(mesh->getBoundingBox());
- }
- else
- {
- _bounds.box->set(Vector3::zero(), Vector3::zero());
- }
- bool empty = _bounds.box->isEmpty();
- if (!empty)
- {
- // Transform the box into world space.
- _bounds.box->transform(getWorldMatrix());
- }
- // Merge this world-space bounding box with our childrens' bounding volumes.
- for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
- {
- switch (n->_boundsType)
- {
- case BOX:
- {
- const BoundingBox& childBox = n->getBoundingBox();
- if (!childBox.isEmpty())
- {
- if (empty)
- {
- _bounds.box->set(childBox);
- empty = false;
- }
- else
- {
- _bounds.box->merge(childBox);
- }
- }
- }
- break;
- case SPHERE:
- {
- const BoundingSphere& childSphere = n->getBoundingSphere();
- if (!childSphere.isEmpty())
- {
- if (empty)
- {
- _bounds.box->set(childSphere);
- empty = false;
- }
- else
- {
- _bounds.box->merge(childSphere);
- }
- }
- }
- break;
- }
- }
- }
- return *_bounds.box;
- }
- const BoundingSphere& Node::getBoundingSphere() const
- {
- if (_boundsType != SPHERE)
- {
- return BoundingSphere::empty();
- }
- if (_dirtyBits & NODE_DIRTY_BOUNDS)
- {
- _dirtyBits &= ~NODE_DIRTY_BOUNDS;
- if (_model && _model->getMesh())
- {
- // Use the bounding volume of our model's mesh.
- Mesh* mesh = _model->getMesh();
- _bounds.sphere->set(mesh->getBoundingSphere());
- }
- else
- {
- _bounds.sphere->set(Vector3::zero(), 0);
- }
- bool empty = _bounds.sphere->isEmpty();
- if (!empty)
- {
- // Transform the sphere into world space.
- _bounds.sphere->transform(getWorldMatrix());
- }
- // Merge this world-space bounding sphere with our childrens' bounding volumes.
- for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
- {
- switch (n->getBoundsType())
- {
- case BOX:
- {
- const BoundingBox& childBox = n->getBoundingBox();
- if (!childBox.isEmpty())
- {
- if (empty)
- {
- _bounds.sphere->set(childBox);
- empty = false;
- }
- else
- {
- _bounds.sphere->merge(childBox);
- }
- }
- }
- break;
- case SPHERE:
- {
- const BoundingSphere& childSphere = n->getBoundingSphere();
- if (!childSphere.isEmpty())
- {
- if (empty)
- {
- _bounds.sphere->set(childSphere);
- empty = false;
- }
- else
- {
- _bounds.sphere->merge(childSphere);
- }
- }
- }
- break;
- }
- }
- }
- return *_bounds.sphere;
- }
- Node::BoundsType Node::getBoundsType() const
- {
- return _boundsType;
- }
- void Node::setBoundsType(Node::BoundsType type)
- {
- if (type != _boundsType)
- {
- switch (_boundsType)
- {
- case BOX:
- SAFE_DELETE(_bounds.box);
- break;
- case SPHERE:
- SAFE_DELETE(_bounds.sphere);
- break;
- }
- memset(&_bounds, 0, sizeof(_bounds));
- _boundsType = type;
- switch (_boundsType)
- {
- case BOX:
- _bounds.box = new BoundingBox();
- break;
- case SPHERE:
- _bounds.sphere = new BoundingSphere();
- break;
- }
- // We need to dirty the bounds for the parents in our hierarchy when
- // our bounding volume type changes.
- Node* parent = getParent();
- while (parent)
- {
- parent->_dirtyBits |= NODE_DIRTY_BOUNDS;
- parent = parent->getParent();
- }
- }
- }
- AudioSource* Node::getAudioSource() const
- {
- return _audioSource;
- }
- void Node::setAudioSource(AudioSource* audio)
- {
- if (_audioSource != audio)
- {
- if (_audioSource)
- {
- _audioSource->setNode(NULL);
- SAFE_RELEASE(_audioSource);
- }
-
- _audioSource = audio;
- if (_audioSource)
- {
- _audioSource->addRef();
- _audioSource->setNode(this);
- }
- }
- }
- ParticleEmitter* Node::getParticleEmitter() const
- {
- return _particleEmitter;
- }
- void Node::setParticleEmitter(ParticleEmitter* emitter)
- {
- if (_particleEmitter != emitter)
- {
- if (_particleEmitter)
- {
- _particleEmitter->setNode(NULL);
- SAFE_RELEASE(_particleEmitter);
- }
-
- _particleEmitter = emitter;
- if (_particleEmitter)
- {
- _particleEmitter->addRef();
- _particleEmitter->setNode(this);
- }
- }
- }
- PhysicsRigidBody* Node::getPhysicsRigidBody() const
- {
- return _physicsRigidBody;
- }
- void Node::setPhysicsRigidBody(PhysicsRigidBody::Type type, float mass, float friction,
- float restitution, float linearDamping, float angularDamping)
- {
- SAFE_DELETE(_physicsRigidBody);
-
- if (type != PhysicsRigidBody::SHAPE_NONE)
- _physicsRigidBody = new PhysicsRigidBody(this, type, mass, friction, restitution, linearDamping, angularDamping);
- }
- }
|