Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: addChild and setParentMode via XML-loading

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