Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: reimplemented a greate part of PNode, so now it uses only relCoord/relDir to calculate the absolute direction
calling setAbsDir will invoke setRelDir in the process

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