// Copyright (C) 1996 Keith Whitwell. // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING in the lib3d distribution. #include float Node::D; Matrix4 Node::cvvToDevice; Node::Node() : dirtyTransform( true ), child( 0 ), next( 0 ), parent( 0 ) { objectToParent.setIdentity(); objectToCvv.setIdentity(); } Node::Node( Node &parent ) : dirtyTransform( true ), child( 0 ), next( parent.child ), parent( &parent ) { parent.child = this; objectToParent.setIdentity(); objectToCvv.setIdentity(); } Node::~Node() { delete child; delete next; } void Node::adopt( Node *child ) { if (child->parent != 0) { cout << "Adopting an already-parented Node is not yet implemented." << endl; abort(); // Later this will rework the transformations so that the Node // retains its world-space position, but will now move with its new // parent. Eg plane dropping a bomb, the bomb changes ownership to // the world (sort of). // transform vertices by // (this->objectToCvv.inverse() . child->objectToCvv) } child->parent = this; child->next = this->child; this->child = child; } void Node::recalculateHierarchy(bool dirtyParent, const Matrix34& parentToCvv ) { if_debug { debug() << "rendering " << " dirtyParent: " << dirtyParent << " dirtySelf: " << isDirty() << endlog; } if ((dirtyParent |= dirtyTransform)) { recalculateTransforms( parentToCvv ); } for (Node *x = child; x ; x = x->next) { x->recalculateHierarchy(dirtyParent, objectToCvv); } } void Node::setTransform( const Matrix34 &newlocal ) { objectToParent = newlocal; dirtyTransform = true; } void Node::recalculateTransforms( const Matrix34 &parentToCvv ) { objectToCvv.mul(parentToCvv, objectToParent); dirtyTransform = false; if_debug { debug() << "objectToParent: " << objectToParent << endlog; debug() << "objectToCvv: " << objectToCvv << endlog; } } const Node * Node::getWorld() const { const Node *world; for (world = this ; world->parent ; world = world->parent); return world; } Node * Node::getWorld() { Node *world; for (world = this ; world->parent ; world = world->parent); return world; } bool Node::isTarnished() const { debug() << "Checking whether tarnished" << endlog; const Node *ob; for (ob = this ; ob->parent ; ob = ob->parent) { if (ob->isDirty()) { debug() << "tarnished because "<< ob->getName() << " is dirty " << endlog; return true; } } debug() << "Not tarnished" << endlog; return false; } void Node::calculateObjectToWorld( Matrix34 &toWorld ) const { toWorld.setIdentity(); for (const Node *x = this ; x->parent ; x = x->parent) { toWorld.premul(x->objectToParent); } } void Node::setLookAt(const Vector3 &from, const Vector3 &at, const Vector3 &up) { if_debug { debug() << "Setting lookat: from: " << from << " at: " << at << " up: " << up << endlog; } Matrix34 tmp; tmp.setLookAt(from, at, up); objectToParent.invert(tmp); dirtyTransform = true; } Node * Node::getNextNamed( const char *name ) { // Continue a depth first preorder traverse from the current object. Node *x = this; while (x) { if (x->child) { while (x->child) { x = x->child; if (strcmp(x->getName(), name) == 0) return x; } } while (x) { if (x->next) { x = x->next; if (strcmp(x->getName(), name) == 0) return x; break; } else { x = x->parent; } } } return 0; } void Node::render( Viewport &, const Light *, uint, uint ) { }