Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: doxygen-tags

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