/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli co-programmer: \todo Smooth-Parent: delay, speed */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_PNODE #include "p_node.h" #include "stdincl.h" #include "compiler.h" #include "error.h" #include "debug.h" #include "list.h" #include "vector.h" #include "null_parent.h" //#include "vector.h" //#include "quaternion.h" using namespace std; /** \brief standard constructor \todo this constructor is not jet implemented - do it */ PNode::PNode () { init(NULL); NullParent* np = NullParent::getInstance(); np->addChild(this); } /** \brief constructor with coodinates \param absCoordinate the Absolute coordinate of the Object \param parent The parent-node of this node. */ PNode::PNode (const Vector& absCoordinate, PNode* parent ) { this->init(parent); this->absCoordinate = absCoordinate; if (likely(parent != NULL)) { this->relCoordinate = this->absCoordinate - parent->getAbsCoor(); parent->addChild (this); } } /** \brief standard deconstructor */ PNode::~PNode () { tIterator* iterator = this->children->getIterator(); PNode* pn = iterator->nextElement(); while( pn != NULL) { delete pn; pn = iterator->nextElement(); } delete iterator; /* this deletes all children in the list */ delete this->children; this->parent = NULL; delete []this->objectName; } void PNode::init(PNode* parent) { this->children = new tList(); this->bRelCoorChanged = true; this->bAbsCoorChanged = false; this->bRelDirChanged = true; this->bAbsDirChanged = false; this->parent = parent; this->objectName = NULL; } /** \brief get relative coordinates \returns relative coordinates to its parent the reference that is returned is a pointer to the real relCoor, so don't change it unless you realy know what you are doing. */ //Vector* PNode::getRelCoor () const /** \brief set relative coordinates \param relCoord relative coordinates to its parent it is very importand, that you use this function, if you want to update the relCoordinates. If you don't use this, the PNode won't recognize, that something has changed and won't update the children Nodes. */ /* void PNode::setRelCoor (Vector* relCoord) { this->bRelCoorChanged = true; *this->relCoordinate = *relCoord; } */ /** \brief set relative coordinates \param relCoord relative coordinates to its parent it is very importand, that you use this function, if you want to update the relCoordinates. If you don't use this, the PNode won't recognize, that something has changed and won't update the children Nodes. */ void PNode::setRelCoor (const Vector& relCoord) { this->bRelCoorChanged = true; this->relCoordinate = relCoord; } /** \brief get absolute coordinates \returns absolute coordinates from (0,0,0) */ //Vector PNode::getAbsCoor () const /** \param absCoord set absolute coordinate it is very importand, that you use this function, if you want to update the absCoordinates. If you don't use this, the PNode won't recognize, that something has changed and won't update the children Nodes. */ void PNode::setAbsCoor (const Vector& absCoord) { this->bAbsCoorChanged = true; this->absCoordinate = absCoord; } /** \brief shift coordinate (abs and rel) \param shift vector this function shifts the current coordinates about the vector shift. this is usefull because from some place else you can: PNode* someNode = ...; Vector objectMovement = calculateShift(); someNode->shiftCoor(objectMovement); elsewhere you would have to: PNode* someNode = ...; Vector objectMovement = calculateShift(); Vector currentCoor = someNode->getRelCoor(); Vector newCoor = currentCoor + objectMovement; someNode->setRelCoor(newCoor); yea right... shorter... */ void PNode::shiftCoor (const Vector& shift) { if( unlikely(this->bAbsCoorChanged)) { this->absCoordinate += shift; } else { this->relCoordinate += shift; this->bRelCoorChanged = true; } } /** \brief get relative direction \returns relative direction to its parent */ //Quaternion* PNode::getRelDir () const /** \brief set relative direction \param relDir to its parent it is very importand, that you use this function, if you want to update the relDirection. If you don't use this, the PNode won't recognize, that something has changed and won't update the children Nodes. */ void PNode::setRelDir (const Quaternion& relDir) { this->bRelCoorChanged = true; this->relDirection = relDir; } /** \brief gets the absolute direction (0,0,1) \returns absolute coordinates */ //Quaternion PNode::getAbsDir () const /** \brief sets the absolute direction (0,0,1) \param absDir absolute coordinates it is very importand, that you use this function, if you want to update the absDirection. If you don't use this, the PNode won't recognize, that something has changed and won't update the children Nodes. */ void PNode::setAbsDir (const Quaternion& absDir) { this->bAbsDirChanged = true; this->absDirection = absDir; } /** \brief shift coordinate (abs and rel) \param shift vector this function shifts the current coordinates about the vector shift. this is usefull because from some place else you can: PNode* someNode = ...; Quaternion objectMovement = calculateShift(); someNode->shiftCoor(objectMovement); elsewhere you would have to: PNode* someNode = ...; Quaternion objectMovement = calculateShift(); Quaternion currentCoor = someNode->getRelCoor(); Quaternion newCoor = currentCoor + objectMovement; someNode->setRelCoor(newCoor); yea right... shorter... \todo implement this */ void PNode::shiftDir (const Quaternion& shift) { this->bRelDirChanged = true; this->relDirection = this->relDirection * shift; } /** \brief adds a child and makes this node to a parent \param pNode child reference \param mode on which changes the child should also change ist state use this to add a child to this node. */ void PNode::addChild (PNode* pNode, int parentingMode) { if( likely(pNode->parent != NULL)) { PRINTF(3)("PNode::addChild() - reparenting node: removing it and adding it again\n"); pNode->parent->children->remove(pNode); } pNode->mode = parentingMode; pNode->parent = this; this->children->add(pNode); } /** \brief removes a child from the node \param pNode the child to remove from this pNode. Children from pNode will not be lost, they are referenced to NullPointer */ void PNode::removeChild (PNode* pNode) { pNode->remove(); this->children->remove (pNode); pNode->parent = NULL; } /** \brief remove this pnode from the tree and adds all following to NullParent this can be the case, if an entity in the world is been destroyed. */ void PNode::remove() { NullParent* nullParent = NullParent::getInstance(); tIterator* iterator = this->children->getIterator(); PNode* pn = iterator->nextElement(); while( pn != NULL) { nullParent->addChild(pn, pn->getMode()); pn = iterator->nextElement(); } delete iterator; this->parent->children->remove(this); } /** \brief sets the parent of this PNode \param parent the Parent to set */ void PNode::setParent (PNode* parent) { parent->addChild(this); } /** \brief set the mode of this parent manualy \param mode the mode of the bind-type. */ void PNode::setMode (int parentingMode) { this->mode = parentingMode; } /** \brief gets the mode of this parent manualy \return the mode of the bind-type. */ int PNode::getMode() const { return this->mode; } /** \brief has to be called, if the parent coordinate has changed normaly this will be done by the parent itself automaticaly. If you call this, you will force an update of the coordinated of the node. */ /* void PNode::parentCoorChanged () { this->bRelCoorChanged = true; } */ /** \brief has to be called, if the parent direction has changed normaly this will be done by the parent itself automaticaly. If you call this, you will force an update of the direction of the node. */ /* void PNode::parentDirChanged () { this->bRelDirChanged = true; } */ /** \brief updates the absCoordinate/absDirection \param timeStamp The timestanp used for to look if calculations should be done this is used to go through the parent-tree to update all the absolute coordinates and directions. this update should be done by the engine, so you don't have to worry, normaly... */ void PNode::update (float dt) { this->lastAbsCoordinate = this->absCoordinate; PRINTF(4)("PNode::update - %s - (%f, %f, %f)\n", this->objectName, this->absCoordinate.x, this->absCoordinate.y, this->absCoordinate.z); if( likely(this->mode & PNODE_MOVEMENT)) { if( unlikely(this->bAbsCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /* if you have set the absolute coordinates this overrides all other changes */ this->relCoordinate = this->absCoordinate - parent->getAbsCoor (); } if( likely(this->bRelCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /*this is bad style... must be deleted later - just for testing*/ /* if( unlikely(this->parent == NULL)) { *this->absCoordinate = *this->relCoordinate; } else */ this->absCoordinate = parent->getAbsCoor() + this->relCoordinate; /* update the current absCoordinate */ } } if( this->mode & PNODE_LOCAL_ROTATE) { if( unlikely(this->bAbsDirChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /* if you have set the absolute coordinates this overrides all other changes */ this->relDirection = this->absDirection - parent->getAbsDir(); } else if( likely(this->bRelDirChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /* update the current absDirection - remember * means rotation around sth.*/ this->absDirection = parent->getAbsDir() * this->relDirection; } } if( this->mode & PNODE_ROTATE_MOVEMENT) { if( unlikely(this->bAbsCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /* if you have set the absolute coordinates this overrides all other changes */ this->relCoordinate = this->absCoordinate - parent->getAbsCoor (); } else if( likely(this->bRelCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/) { /*this is bad style... must be deleted later - just for testing*/ /*if( this->parent == NULL) *this->absCoordinate = *this->relCoordinate; else*/ this->absCoordinate = parent->getAbsCoor() + parent->getAbsDir().apply(this->relCoordinate); /* update the current absCoordinate */ } } tIterator* iterator = this->children->getIterator(); //PNode* pn = this->children->enumerate(); PNode* pn = iterator->nextElement(); while( pn != NULL) { /* if this node has changed, make sure, that all children are updated also */ if( likely(this->bRelCoorChanged || this->bAbsCoorChanged)) pn->parentCoorChanged (); if( likely(this->bRelDirChanged || this->bAbsDirChanged)) pn->parentDirChanged (); pn->update(dt); //pn = this->children->nextElement(); pn = iterator->nextElement(); } delete iterator; this->velocity = (this->absCoordinate - this->lastAbsCoordinate) / dt; this->timeStamp = timeStamp; this->bRelCoorChanged = false; this->bAbsCoorChanged = false; this->bRelDirChanged = false; this->bAbsDirChanged = false; } /** \brief tick \param dt time to tick */ void PNode::processTick (float dt) { //this->tick (dt); /* PNode* pn = this->children->enumerate(); while( pn != NULL) { pn->processTick (dt); pn = this->children->nextElement(); } */ } /** \brief displays some information about this pNode */ void PNode::debug() { PRINTF(2)("PNode::debug() - absCoord: (%f, %f, %f)\n", this->absCoordinate.x, this->absCoordinate.y, this->absCoordinate.z); } /** \brief set the name of the node for debug purposes realy usefull, not used to work properly */ void PNode::setName (const char* newName) { this->objectName = new char[strlen(newName)+1]; strcpy(this->objectName,newName); } /** \brief gets the name of the node */ const char* PNode::getName () { return this->objectName; }