Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: softPNode finished for Movement only

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