Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/lib/coord/p_node.cc @ 4917

Last change on this file since 4917 was 4870, checked in by bensch, 19 years ago

orxonox/trunk: fixed major bug in PNode deletion cycle.
The Node did not unsubscribe itself at its parent

File size: 18.0 KB
Line 
1
2
3/*
4   orxonox - the future of 3D-vertical-scrollers
5
6   Copyright (C) 2004 orx
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   ### File Specific:
14   main-programmer: Patrick Boenzli
15   co-programmer:
16
17   @todo Smooth-Parent: delay, speed
18*/
19
20#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_PNODE
21
22#include "p_node.h"
23#include "null_parent.h"
24
25#include "load_param.h"
26#include "class_list.h"
27
28#include "stdincl.h"
29#include "compiler.h"
30#include "error.h"
31#include "debug.h"
32#include "list.h"
33#include "vector.h"
34
35//#include "vector.h"
36//#include "quaternion.h"
37
38using namespace std;
39
40
41/**
42 *  standard constructor
43*/
44PNode::PNode ()
45{
46  init(NULL);
47
48  NullParent::getInstance()->addChild(this);
49}
50
51/**
52 * @param root the load-Element for the PNode
53*/
54PNode::PNode(const TiXmlElement* root)
55{
56  this->init(NULL);
57  this->loadParams(root);
58
59  NullParent::getInstance()->addChild(this);
60}
61
62
63/**
64 *  constructor with coodinates
65 * @param absCoordinate the Absolute coordinate of the Object
66 * @param parent The parent-node of this node.
67*/
68PNode::PNode (const Vector& absCoordinate, PNode* parent )
69{
70  this->init(parent);
71
72  this->absCoordinate = absCoordinate;
73
74  if (likely(parent != NULL))
75  {
76    this->relCoordinate = this->absCoordinate - parent->getAbsCoor();
77    parent->addChild (this);
78  }
79}
80
81/**
82 *  standard deconstructor
83*/
84PNode::~PNode ()
85{
86  tIterator<PNode>* iterator = this->children->getIterator();
87  PNode* pn = iterator->nextElement();
88  while( pn != NULL)
89    {
90      delete pn;
91      pn = iterator->nextElement();
92    }
93  delete iterator;
94  /* this deletes all children in the list */
95  delete this->children;
96  if (this->parent)
97    this->parent->removeChild(this);
98}
99
100/**
101 *  initializes a PNode
102 * @param parent the parent for this PNode
103*/
104void PNode::init(PNode* parent)
105{
106  this->setClassID(CL_PARENT_NODE, "PNode");
107  this->children = new tList<PNode>();
108  this->bRelCoorChanged = true;
109  this->bAbsCoorChanged = false;
110  this->bRelDirChanged = true;
111  this->bAbsDirChanged = false;
112  this->parent = parent;
113}
114
115/**
116 *  loads parameters of the PNode
117 * @param root the XML-element to load the properties of
118*/
119void PNode::loadParams(const TiXmlElement* root)
120{
121  static_cast<BaseObject*>(this)->loadParams(root);
122
123  LoadParam<PNode>(root, "rel-coor", this, &PNode::setRelCoor)
124      .describe("Sets The relative position of the Node to its parent.");
125
126  LoadParam<PNode>(root, "abs-coor", this, &PNode::setAbsCoor)
127      .describe("Sets The absolute Position of the Node.");
128
129  LoadParam<PNode>(root, "rel-dir", this, &PNode::setRelDir)
130      .describe("Sets The relative rotation of the Node to its parent.");
131
132  LoadParam<PNode>(root, "abs-dir", this, &PNode::setAbsDir)
133      .describe("Sets The absolute rotation of the Node.");
134
135  LoadParam<PNode>(root, "parent", this, &PNode::setParent)
136      .describe("the Name of the Parent of this PNode");
137
138  LoadParam<PNode>(root, "parent-mode", this, &PNode::setParentMode)
139      .describe("the mode to connect this node to its parent ()");
140
141  // cycling properties
142  if (root != NULL)
143  {
144    const TiXmlElement* element = root->FirstChildElement();
145    while (element != NULL)
146    {
147      LoadParam<PNode>(root, "parent", this, &PNode::addChild, true)
148          .describe("adds a new Child to the current Node.");
149
150      element = element->NextSiblingElement();
151    }
152  }
153}
154
155/**
156 *  set relative coordinates
157 * @param relCoord relative coordinates to its parent
158
159   it is very importand, that you use this function, if you want to update the
160   relCoordinates. If you don't use this, the PNode won't recognize, that something
161   has changed and won't update the children Nodes.
162*/
163void PNode::setRelCoor (const Vector& relCoord)
164{
165  this->bRelCoorChanged = true;
166  this->relCoordinate = relCoord;
167}
168
169/**
170 *  set relative coordinates
171 * @param x x-relative coordinates to its parent
172 * @param y y-relative coordinates to its parent
173 * @param z z-relative coordinates to its parent
174   \see  void PNode::setRelCoor (const Vector& relCoord)
175*/
176void PNode::setRelCoor (float x, float y, float z)
177{
178  this->setRelCoor(Vector(x, y, z));
179}
180
181/**
182 * @param absCoord set absolute coordinate
183
184   it is very importand, that you use this function, if you want to update the
185   absCoordinates. If you don't use this, the PNode won't recognize, that something
186   has changed and won't update the children Nodes.
187*/
188void PNode::setAbsCoor (const Vector& absCoord)
189{
190  this->bAbsCoorChanged = true;
191  this->absCoordinate = absCoord;
192}
193
194/**
195 * @param x x-coordinate.
196 * @param y y-coordinate.
197 * @param z z-coordinate.
198 * \see void PNode::setAbsCoor (const Vector& absCoord)
199 */
200void PNode::setAbsCoor(float x, float y, float z)
201{
202  this->setAbsCoor(Vector(x, y, z));
203}
204
205/**
206 *  shift coordinate (abs and rel)
207 * @param shift shift vector
208
209   this function shifts the current coordinates about the vector shift. this is
210   usefull because from some place else you can:
211   PNode* someNode = ...;
212   Vector objectMovement = calculateShift();
213   someNode->shiftCoor(objectMovement);
214
215   elsewhere you would have to:
216   PNode* someNode = ...;
217   Vector objectMovement = calculateShift();
218   Vector currentCoor = someNode->getRelCoor();
219   Vector newCoor = currentCoor + objectMovement;
220   someNode->setRelCoor(newCoor);
221
222   yea right... shorter...
223
224*/
225void PNode::shiftCoor (const Vector& shift)
226{
227
228  if( unlikely(this->bAbsCoorChanged))
229    {
230      this->absCoordinate += shift;
231    }
232  else
233    {
234      this->relCoordinate += shift;
235      this->bRelCoorChanged = true;
236    }
237}
238
239/**
240 *  set relative direction
241 * @param relDir to its parent
242
243   it is very importand, that you use this function, if you want to update the
244   relDirection. If you don't use this, the PNode won't recognize, that something
245   has changed and won't update the children Nodes.
246*/
247void PNode::setRelDir (const Quaternion& relDir)
248{
249  this->bRelCoorChanged = true;
250  this->relDirection = relDir;
251}
252
253/**
254 * @see void PNode::setRelDir (const Quaternion& relDir)
255 * @param x the x direction
256 * @param y the y direction
257 * @param z the z direction
258 *
259 * main difference is, that here you give a directional vector, that will be translated into a Quaternion
260 */
261void PNode::setRelDir (float x, float y, float z)
262{
263  this->setRelDir(Quaternion(Vector(x,y,z), Vector(0,1,0)));
264}
265
266/**
267 *  sets the absolute direction (0,0,1)
268 * @param absDir absolute coordinates
269
270   it is very importand, that you use this function, if you want to update the
271   absDirection. If you don't use this, the PNode won't recognize, that something
272   has changed and won't update the children Nodes.
273*/
274void PNode::setAbsDir (const Quaternion& absDir)
275{
276  this->bAbsDirChanged = true;
277  this->absDirection = absDir;
278}
279
280/**
281 * @see void PNode::setAbsDir (const Quaternion& relDir)
282 * @param x the x direction
283 * @param y the y direction
284 * @param z the z direction
285 *
286 * main difference is, that here you give a directional vector, that will be translated into a Quaternion
287 */
288void PNode::setAbsDir (float x, float y, float z)
289{
290  this->setAbsDir(Quaternion(Vector(x,y,z), Vector(0,1,0)));
291}
292
293/**
294 *  shift coordinate (abs and rel)
295 * @param shift vector
296
297   this function shifts the current coordinates about the vector shift. this is
298   usefull because from some place else you can:
299   PNode* someNode = ...;
300   Quaternion objectMovement = calculateShift();
301   someNode->shiftCoor(objectMovement);
302
303   elsewhere you would have to:
304   PNode* someNode = ...;
305   Quaternion objectMovement = calculateShift();
306   Quaternion currentCoor = someNode->getRelCoor();
307   Quaternion newCoor = currentCoor + objectMovement;
308   someNode->setRelCoor(newCoor);
309
310   yea right... shorter...
311
312   @todo implement this
313*/
314void PNode::shiftDir (const Quaternion& shift)
315{
316  this->bRelDirChanged = true;
317  this->relDirection = this->relDirection * shift;
318}
319
320/**
321 *  adds a child and makes this node to a parent
322 * @param pNode child reference
323 * @param parentMode on which changes the child should also change ist state
324
325   use this to add a child to this node.
326*/
327void PNode::addChild (PNode* pNode, int parentMode)
328{
329  if( likely(pNode->parent != NULL))
330    {
331      PRINTF(3)("PNode::addChild() - reparenting node: removing it and adding it again\n");
332      pNode->parent->children->remove(pNode);
333    }
334  pNode->parentMode = parentMode;
335  pNode->parent = this;
336  this->children->add(pNode);
337}
338
339/**
340 * @see PNode::addChild(PNode* parent);
341 * @param childName the name of the child to add to this PNode
342 */
343void PNode::addChild (const char* childName)
344{
345  PNode* childNode = dynamic_cast<PNode*>(ClassList::getObject(childName, CL_PARENT_NODE));
346  if (childNode != NULL)
347    this->addChild(childNode);
348}
349
350
351/**
352 *  removes a child from the node
353 * @param pNode the child to remove from this pNode.
354
355   Children from pNode will not be lost, they are referenced to NullPointer
356*/
357void PNode::removeChild (PNode* pNode)
358{
359  pNode->remove();
360  this->children->remove (pNode);
361  pNode->parent = NULL;
362}
363
364
365/**
366 *  remove this pnode from the tree and adds all following to NullParent
367
368   this can be the case, if an entity in the world is been destroyed.
369*/
370void PNode::remove()
371{
372  NullParent* nullParent = NullParent::getInstance();
373
374  tIterator<PNode>* iterator = this->children->getIterator();
375  PNode* pn = iterator->nextElement();
376
377  while( pn != NULL)
378    {
379      nullParent->addChild(pn, pn->getParentMode());
380      pn = iterator->nextElement();
381    }
382  delete iterator;
383  this->parent->children->remove(this);
384}
385
386
387/**
388 *  sets the parent of this PNode
389 * @param parent the Parent to set
390*/
391void PNode::setParent (PNode* parent)
392{
393  parent->addChild(this);
394}
395
396/**
397 * @see PNode::setParent(PNode* parent);
398 * @param parentName the name of the Parent to set to this PNode
399 */
400void PNode::setParent (const char* parentName)
401{
402  PNode* parentNode = dynamic_cast<PNode*>(ClassList::getObject(parentName, CL_PARENT_NODE));
403  if (parentNode != NULL)
404    parentNode->addChild(this);
405}
406
407/**
408 *  set the mode of this parent manualy
409 * @param parentMode the mode of the bind-type.
410*/
411void PNode::setParentMode (PARENT_MODE parentMode)
412{
413  this->parentMode = parentMode;
414}
415
416/**
417 *  sets the mode of this parent manually
418 * @param parentMode a String representing this parentingMode
419 */
420void PNode::setParentMode (const char* parentingMode)
421{
422  if (!strcmp(parentingMode, "local-rotate"))
423    this->setParentMode(PNODE_LOCAL_ROTATE);
424  else  if (!strcmp(parentingMode, "rotate-movement"))
425    this->setParentMode(PNODE_ROTATE_MOVEMENT);
426  else  if (!strcmp(parentingMode, "movement"))
427    this->setParentMode(PNODE_MOVEMENT);
428  else  if (!strcmp(parentingMode, "all"))
429    this->setParentMode(PNODE_ALL);
430  else  if (!strcmp(parentingMode, "rotate-and-move"))
431    this->setParentMode(PNODE_ROTATE_AND_MOVE);
432}
433
434
435/**
436 *  has to be called, if the parent coordinate has changed
437
438   normaly this will be done by the parent itself automaticaly. If you call this, you
439   will force an update of the coordinated of the node.
440*/
441/*
442void PNode::parentCoorChanged ()
443{
444  this->bRelCoorChanged = true;
445}
446*/
447
448/**
449 *  updates the absCoordinate/absDirection
450 * @param dt The time passed since the last update
451
452   this is used to go through the parent-tree to update all the absolute coordinates
453   and directions. this update should be done by the engine, so you don't have to
454   worry, normaly...
455*/
456void PNode::update (float dt)
457{
458  if( likely(this->parent != NULL))
459    {
460      this->lastAbsCoordinate = this->absCoordinate;
461
462      PRINTF(4)("PNode::update - %s - (%f, %f, %f)\n", this->getName(), this->absCoordinate.x, this->absCoordinate.y, this->absCoordinate.z);
463
464
465      if( likely(this->parentMode & PNODE_MOVEMENT))
466        {
467          if( unlikely(this->bAbsCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
468            {
469              /* if you have set the absolute coordinates this overrides all other changes */
470              this->relCoordinate = this->absCoordinate - parent->getAbsCoor ();
471            }
472          if( likely(this->bRelCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
473
474            {
475              /*this is bad style... must be deleted later - just for testing*/
476
477              /*
478                if( unlikely(this->parent == NULL))
479                {
480                *this->absCoordinate = *this->relCoordinate;
481                }
482                else */
483              this->absCoordinate = parent->getAbsCoor() + this->relCoordinate;       /* update the current absCoordinate */
484            }
485        }
486
487      if( this->parentMode & PNODE_LOCAL_ROTATE)
488        {
489          if( unlikely(this->bAbsDirChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
490            {
491              /* if you have set the absolute coordinates this overrides all other changes */
492              this->relDirection = this->absDirection - parent->getAbsDir();
493            }
494          else if( likely(this->bRelDirChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
495            {
496              /* update the current absDirection - remember * means rotation around sth.*/
497              this->absDirection = parent->getAbsDir() * this->relDirection;
498            }
499        }
500
501      if( this->parentMode & PNODE_ROTATE_MOVEMENT)
502        {
503          if( unlikely(this->bAbsCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
504            {
505              /* if you have set the absolute coordinates this overrides all other changes */
506              this->relCoordinate = this->absCoordinate - parent->getAbsCoor ();
507            }
508          else if( likely(this->bRelCoorChanged) /*&& this->timeStamp != DataTank::timeStamp*/)
509            {
510              /*this is bad style... must be deleted later - just for testing*/
511              /*if( this->parent == NULL)
512               *this->absCoordinate = *this->relCoordinate;
513               else*/
514              this->absCoordinate = parent->getAbsCoor() + parent->getAbsDir().apply(this->relCoordinate);            /* update the current absCoordinate */
515            }
516        }
517
518
519      tIterator<PNode>* iterator = this->children->getIterator();
520      //PNode* pn = this->children->enumerate();
521      PNode* pn = iterator->nextElement();
522      while( pn != NULL)
523        {
524          /* if this node has changed, make sure, that all children are updated also */
525          if( likely(this->bRelCoorChanged || this->bAbsCoorChanged))
526            pn->parentCoorChanged ();
527          if( likely(this->bRelDirChanged || this->bAbsDirChanged))
528            pn->parentDirChanged ();
529
530          pn->update(dt);
531          //pn = this->children->nextElement();
532          pn = iterator->nextElement();
533        }
534      delete iterator;
535
536      this->velocity = (this->absCoordinate - this->lastAbsCoordinate) / dt;
537      this->bRelCoorChanged = false;
538      this->bAbsCoorChanged = false;
539      this->bRelDirChanged = false;
540      this->bAbsDirChanged = false;
541    }
542  else
543    {
544      PRINTF(4)("NullParent::update - (%f, %f, %f)\n", this->absCoordinate.x, this->absCoordinate.y, this->absCoordinate.z);
545      this->absCoordinate = this->relCoordinate;
546      this->absDirection = this->getAbsDir () * this->relDirection;
547
548      tIterator<PNode>* iterator = this->children->getIterator();
549      //PNode* pn = this->children->enumerate ();
550      PNode* pn = iterator->nextElement();
551      while( pn != NULL)
552      {
553        /* if this node has changed, make sure, that all children are updated also */
554          if( this->bRelCoorChanged || this->bAbsCoorChanged)
555            pn->parentCoorChanged ();
556          if( this->bRelDirChanged || this->bAbsDirChanged)
557            pn->parentDirChanged ();
558          pn->update (dt);
559          //pn = this->children->nextElement ();
560          pn = iterator->nextElement();
561        }
562      delete iterator;
563      this->bRelCoorChanged = false;
564      this->bAbsCoorChanged = false;
565      this->bRelDirChanged = false;
566      this->bAbsDirChanged = false;
567    }
568}
569
570/**
571 *  displays some information about this pNode
572 * @param depth The deph into which to debug the children of this PNode to.
573  (0: all children will be debugged, 1: only this PNode, 2: this and direct children...)
574 * @param level The n-th level of the Node we draw (this is internal and only for nice output)
575*/
576void PNode::debug(unsigned int depth, unsigned int level) const
577{
578  for (unsigned int i = 0; i < level; i++)
579    PRINT(0)(" |");
580  if (this->children->getSize() > 0)
581    PRINT(0)(" +");
582  else
583    PRINT(0)(" -");
584  PRINT(0)("PNode(%s::%s) - absCoord: (%0.2f, %0.2f, %0.2f), relCoord(%0.2f, %0.2f, %0.2f)\n",
585           this->getClassName(),
586           this->getName(),
587           this->absCoordinate.x,
588           this->absCoordinate.y,
589           this->absCoordinate.z,
590           this->relCoordinate.x,
591           this->relCoordinate.y,
592           this->relCoordinate.z );
593  if (depth >= 2 || depth == 0)
594  {
595    tIterator<PNode>* iterator = this->children->getIterator();
596      //PNode* pn = this->children->enumerate ();
597    PNode* pn = iterator->nextElement();
598    while( pn != NULL)
599    {
600      if (depth == 0)
601        pn->debug(0, level + 1);
602      else
603        pn->debug(depth - 1, level +1);
604      pn = iterator->nextElement();
605    }
606    delete iterator;
607  }
608}
609
610/**
611   displays the PNode at its position with its rotation as a cube.
612*/
613void PNode::debugDraw(float size) const
614{
615  glMatrixMode(GL_MODELVIEW);
616  glPushMatrix();
617  float matrix[4][4];
618
619  /* translate */
620  glTranslatef (this->getAbsCoor ().x,
621                this->getAbsCoor ().y,
622                this->getAbsCoor ().z);
623  /* rotate */
624  this->getAbsDir ().matrix (matrix);
625  glMultMatrixf((float*)matrix);
626  {
627    glBegin(GL_LINE_STRIP);
628    glVertex3f( .5,  .5, -.5);
629    glVertex3f( .5,  .5,  .5);
630    glVertex3f(-.5,  .5,  .5);
631    glVertex3f(-.5, -.5,  .5);
632    glVertex3f( .5,  .5, -.5);
633    glVertex3f( .5, -.5, -.5);
634    glVertex3f(-.5, -.5, -.5);
635    glVertex3f(-.5,  .5, -.5);
636    glEnd();
637    glBegin(GL_LINE_STRIP);
638    glVertex3f(-.5, -.5, -.5);
639    glVertex3f(-.5, -.5,  .5);
640    glVertex3f( .5, -.5,  .5);
641    glVertex3f( .5, -.5, -.5);
642    glEnd();
643    glBegin(GL_LINES);
644    glVertex3f( .5, -.5,  .5);
645    glVertex3f( .5,  .5,  .5);
646    glVertex3f(-.5, -.5,  .5);
647    glVertex3f(-.5,  .5,  .5);
648    glEnd();
649  }
650
651  glPopMatrix();
652}
Note: See TracBrowser for help on using the repository browser.