Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/util/track/track_manager.cc @ 4499

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

orxonox/trunk: cycling read-in of parameters should work now… this is quite tricky, and the TrackManager has to be rewritten in some parts…. :(

File size: 34.2 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: Benjamin Grauer
13   co-programmer: ...
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_TRACK_MANAGER
17
18#include "track_manager.h"
19
20#include "base_object.h"
21#include "p_node.h"
22#include "track_node.h"
23#include "stdincl.h"
24#include "list.h"
25#include "text_engine.h"
26#include "t_animation.h"
27#include "load_param.h"
28
29
30#include "tinyxml.h"
31#include "substring.h"
32
33#include <stdarg.h>
34
35using namespace std;
36
37/**
38   \brief initializes a TrackElement (sets the default values)
39*/
40TrackElement::TrackElement(void)
41{
42  this->isFresh = true;
43  this->isHotPoint = false;
44  this->isSavePoint = false;
45  this->isFork = false;
46  this->isJoined = false;
47  this->mainJoin = false;
48  this->ID = -1;
49  this->startingTime = 0;
50  this->duration = TMAN_DEFAULT_DURATION;
51  this->endTime = 1;
52  this->jumpTime = 0;
53  this->width = TMAN_DEFAULT_WIDTH;
54  this->nodeCount = 0;
55  this->curve = NULL;
56  this->childCount = 0;
57  this->children = NULL;
58  this->name = NULL;
59
60  this->history = NULL;
61
62  this->subject = NULL;
63  this->condFunc = &TrackElement::random;
64}
65
66/**
67    \brief destroys all alocated memory)
68    \todo eventually when deleting a TrackElement you would not like to delete all its preceding TrackElements
69*/
70TrackElement::~TrackElement(void)
71{
72  // deleting the Name
73  delete []name;
74  // deleting the Curve
75  delete this->curve;
76
77  // deleting all the Children of this TrackNode.
78  if ((!this->isJoined &&this->childCount > 0) 
79      || (this->isJoined && this->mainJoin)) // only if this is the MainJoin.
80    {
81      tIterator<TrackElement>* iterator = this->children->getIterator();
82      TrackElement* enumElem = iterator->nextElement();
83      while (enumElem)
84        {
85          delete enumElem;
86          enumElem = iterator->nextElement();
87        }
88      delete iterator;
89      delete this->children;
90    }
91}
92
93/**
94   \brief Searches through all the TrackElements for trackID.
95   \param trackID The ID to search for.
96   \returns The TrackElement if Found, NULL otherwise.
97*/
98TrackElement* TrackElement::findByID(unsigned int trackID)
99{
100  // return if Found.
101  if (this->ID == trackID)
102    return this;
103  // search all children
104  if (this->childCount > 0)
105    {
106      tIterator<TrackElement>* iterator = this->children->getIterator();
107      TrackElement* enumElem = iterator->nextElement();
108      TrackElement* tmpElem;
109      while (enumElem)
110        {
111          if ((tmpElem = enumElem->findByID(trackID)))
112            return tmpElem;
113          enumElem = iterator->nextElement();
114        }
115      delete iterator;
116    }
117  // if not found
118  return NULL;
119}
120
121
122/**
123   \brief Searches through all the TrackElements for a trackName
124   \param trackName The name to search for.
125   \returns The TrackElement if Found, NULL otherwise.
126*/
127TrackElement* TrackElement::findByName(const char* trackName)
128{
129  // return if Found.
130  if (this->name && !strcmp(this->name, trackName))
131    return this;
132  // search all children
133  if (this->childCount > 0)
134    {
135      tIterator<TrackElement>* iterator = this->children->getIterator();
136      TrackElement* enumElem = iterator->nextElement();
137      TrackElement* tmpElem;
138      while (enumElem)
139        {
140          if ((tmpElem = enumElem->findByName(trackName)))
141            return tmpElem;
142          enumElem = iterator->nextElement();
143        }
144      delete iterator;
145    }
146  // if not found
147  return NULL;
148}
149
150/**
151   \brief checks if there are any BackLoops in the Track (Backloops only
152   \param trackElem the trackElement to check about
153   \param depth the depth to search in
154   \returns true if NO loop was found, false Otherwise
155   You actually have to act on false!!
156   it simply does this by looking if the current trackElem is found again somewhere else in the Track
157
158   \todo this has to be reimplemented
159*/
160bool TrackElement::backLoopCheck(const TrackElement* trackElem, unsigned int depth) const
161{
162  if(depth == 0 || this != trackElem)
163    {
164      if (this->children)
165        {
166          tIterator<TrackElement>* iterator = this->children->getIterator();
167          TrackElement* enumElem = iterator->nextElement();
168          while (enumElem)
169            {
170              if(!enumElem->backLoopCheck(trackElem, depth + 1))
171                return false;
172              enumElem = iterator->nextElement();
173            }
174          delete iterator;
175        }
176    }
177  else
178    return false;
179
180  // only returns if everything worked out
181  return true;
182}
183
184/**
185   \param childCount which child to return
186   \returns the n-the children (starting at 0).
187   Be aware, that when the trackElement has no Children, NULL will be returned
188*/
189TrackElement* TrackElement::getChild(int childCount) const
190{
191  // if the the trackElement has no children return NULL.
192  if (this->childCount == 0)
193    return NULL;
194  // we cannot return the childCount+m's Child, so we return the last.
195  if (childCount > this->childCount)
196    childCount = this->childCount;
197 
198  tIterator<TrackElement>* iterator = this->children->getIterator();
199  TrackElement* enumElem = iterator->nextElement();
200  for (int i = 0; i < childCount; i++)
201    enumElem = iterator->nextElement();
202  delete iterator;
203  return enumElem;
204}
205
206/**
207   \param name the Name to set.
208*/
209void TrackElement::setName(const char* name)
210{
211  //  delete the old name
212  if (this->name)
213    delete []this->name;
214  // if a name was given.
215  if (name)
216    {
217      this->name = new char[strlen(name)+1];
218      strcpy(this->name, name);
219    }
220  else 
221    this->name = NULL;
222}
223
224/**
225   \brief prints out debug information about this TrackElement
226*/
227void TrackElement::debug(void) const
228{
229  PRINT(0)("--== TrackElement:%i ==--", this->ID);
230  if(this->getName())
231    PRINT(0)("--++Name: %s++--", this->getName());
232  if(this->isFresh)
233    PRINT(0)("  -- has not jet eddited in any way --\n");
234  PRINT(0)("\n   TimeTable: startingTime=%f; endTime=%f; duration=%f; jumpTime=%f\n", this->startingTime, this->endTime, this->duration, this->jumpTime);
235  PRINT(0)("   consists of %d Points\n", this->nodeCount);
236  if (this->childCount == 0)
237    PRINT(0)("   has no child\n");
238  else if (this->childCount == 1)
239    PRINT(0)("   has 1 child: =%d=\n", this->getChild(0)->ID);
240  else if (this->childCount > 1)
241    {
242      PRINT(0)("   has %d children: ", this->childCount);
243      //TrackElement* enumElem = this->children->enumerate();
244      tIterator<TrackElement>* iterator = this->children->getIterator();
245      TrackElement* enumElem = iterator->nextElement();
246      while (enumElem)
247        {
248          PRINT(0)("=%d= ", enumElem->ID);
249          enumElem = iterator->nextElement();
250        }
251      delete iterator;
252      PRINT(0)("\n");
253    }
254 
255  if(this->isHotPoint)
256    PRINT(0)("   is a special Point:\n");
257  if(this->isSavePoint)
258    PRINT(0)("    is a SavePoint\n");
259  if(this->isFork)
260    {
261      PRINT(0)("    is A Fork with with %d children.\n", this->childCount);
262    }
263  if(this->isJoined)
264    PRINT(0)("   is Joined at the End\n");
265 
266  if(!this->backLoopCheck(this)) /* this should not happen */
267    PRINT(2)(" THERE IS A BACKLOOP TO THIS ELEMENT\n");
268}
269
270/**
271   \brief CONDITION that chooses the first child for the decision (static)
272   \param nothing Nothing in this function
273   \returns the chosen child
274*/
275int TrackElement::lowest(const void* nothing) const
276{
277  return 0;
278}
279
280/**
281   \brief CONDITION that chooses the last child for the decision (static)
282   \param nothing Nothing in this function
283   \returns the chosen child
284*/
285int TrackElement::highest(const void* nothing) const
286{ 
287  return this->childCount-1;
288}
289
290/**
291   \brief CONDITION that chooses a random child for the decision (static)
292   \param nothing Nothing in this function
293   \returns the chosen child
294*/
295int TrackElement::random(const void* nothing) const
296{
297  int i = (int)floor ((float)rand()/(float)RAND_MAX * (float)this->childCount);
298  if (i >= this->childCount)
299    return this->childCount-1;
300  else 
301    return i;
302}
303
304/**
305   \brief CONDITION that chooses child 0, if the node(probably Player)
306   is left of its parent (z<0)) and 1/right otherwise.
307   \param node The node to act upon.
308   \returns the chosen child
309*/
310int TrackElement::leftRight(const void* node) const
311{
312  PNode* tmpNode = (PNode*)node;
313
314  if (tmpNode->getRelCoor().z < 0)
315    return 0;
316  else 
317    return 1;
318}
319
320
321/**
322   \brief CONDITION that chooses the child, that has the nearest distance to the node (probably player).
323   \param node The node to act upon.
324   \returns the chosen child
325
326   This is rather dangerous, because one must carefully set the points on the curve.
327   The best Way is to set the nodes as wide away of each other as possible,
328   but take into consideration, that if the nodes are to far from a center node, the center will be chosen.
329   (play with this!!).
330*/
331int TrackElement::nearest(const void* node) const
332{
333  PNode* tmpNode = (PNode*)node;
334
335  Vector nodeRelCoord = tmpNode->getRelCoor();
336  float minDist = 100000000;
337  int childNumber = 0;
338  int i = 0;
339
340  //TrackElement* enumElem = this->children->enumerate();
341  tIterator<TrackElement>* iterator = this->children->getIterator();
342  TrackElement* enumElem = iterator->nextElement();
343  while (enumElem)
344    {
345      float dist = (nodeRelCoord - enumElem->curve->getNode(4)).len();
346      if (dist < minDist)
347        {
348          minDist = dist;
349          childNumber = i;
350        }
351      i++;
352      enumElem = iterator->nextElement();
353    }
354  delete iterator;
355
356  PRINTF(4)("PathDecision with nearest algorithm: %d\n", childNumber);
357  return childNumber;
358}
359
360
361////////////////////////
362///// TRACKMANAGER /////
363////////////////////////
364/**
365   \brief standard constructor
366
367*/
368TrackManager::TrackManager(void)
369{
370  this->setClassID(CL_TRACK_MANAGER, "TrackManager");
371 
372  TrackManager::singletonRef = this; // do this because otherwise the TrackNode cannot get The instance of the TrackManager
373
374  PRINTF(3)("Initializing the TrackManager\n");
375  // setting up the First TrackElement
376  this->firstTrackElem = new TrackElement();
377  this->firstTrackElem->ID = 1;
378  this->firstTrackElem->setName("root");
379
380  this->currentTrackElem = firstTrackElem;
381
382  this->curveType = CURVE_BEZIER;
383  this->localTime = 0;
384  this->maxTime = 0;
385  this->trackElemCount = 1;
386
387  this->trackNode = new TrackNode();
388  this->setBindSlave(this->trackNode);
389  // initializing the Text
390  this->trackText = TextEngine::getInstance()->createText("fonts/earth.ttf", 30, TEXT_DYNAMIC, 0, 255, 0);
391  this->trackText->setAlignment(TEXT_ALIGN_SCREEN_CENTER);
392  // initializing the Animation for the Text.
393  this->textAnimation = new tAnimation<Text>(this->trackText, &Text::setBlending);
394  this->textAnimation->addKeyFrame(1.0, 3.0, ANIM_NEG_EXP);
395  this->textAnimation->addKeyFrame(0.0, .001);
396  this->textAnimation->setInfinity(ANIM_INF_CONSTANT);
397}
398
399
400/**
401   \brief loads a trackElement from a TiXmlElement
402   \param root the TiXmlElement to load the Data from
403*/
404bool TrackManager::loadParams( TiXmlElement* root)
405{
406  TiXmlElement* element;
407  TiXmlNode* container;
408  double x, y, z, d;
409       
410  element = root->FirstChildElement();
411       
412  while( element != NULL)
413    {
414      LoadParam<TrackManager>(element, "Point", this, &TrackManager::addPoint, true)
415        .describe("Adds a new Point to the currently selected TrackElement");
416
417      LoadParam<TrackManager>(element, "Duration", this, &TrackManager::setDuration, true)
418        .describe("Sets the Duration of the currently selected TrackElement");
419     
420      LoadParam<TrackManager>(element, "SavePoint", this, &TrackManager::setSavePoint, true);
421
422      /*
423      if( !strcmp( element->Value(), "SavePoint"))
424        {
425          PRINTF(5)("Loaded Savepoint\n");
426          setSavePoint();
427        }
428      */
429      if( !strcmp( element->Value(), "Fork"))
430        {
431          container = element->FirstChild();
432          if( container->ToText())
433            {
434              assert( container->Value() != NULL);
435              PRINTF(4)("Loaded Fork: %s\n", container->Value());
436              forkS(container->Value());
437            }
438        }
439      else if( !strcmp( element->Value(), "Join"))
440        {
441          container = element->FirstChild();
442          if( container->ToText())
443            {
444              assert( container->Value() != NULL);
445              PRINTF0("Loaded Join: %s\n", container->Value());
446              joinS(container->Value());
447            }
448        }
449      else if( !strcmp( element->Value(), "WorkOn"))
450        {
451          container = element->FirstChild();
452          if( container->ToText())
453            {
454              assert( container->Value() != NULL);
455              PRINTF(4)("Loaded WorkOn: %s\n", container->Value());
456              workOn( container->Value());
457            }
458        }
459               
460      element = element->NextSiblingElement();
461    }
462
463}
464
465/**
466   \brief standard destructor
467*/
468TrackManager::~TrackManager(void)
469{
470  PRINTF(3)("Destruct TrackManager\n");
471
472  PRINTF(4)("Deleting all the TrackElements\n");
473  delete this->firstTrackElem;
474
475  // the tracknode should be deleted here, but is deleted by pNode: -> null_parent
476
477  // we do not have a TrackManager anymore
478  TrackManager::singletonRef = NULL;
479}
480
481//! Singleton Reference to TrackManager
482TrackManager* TrackManager::singletonRef = NULL;
483
484// INITIALIZE //
485/**
486   \brief reserves Space for childCount children
487   \param childCount The Count of children to make space for.
488   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
489*/
490void TrackManager::initChildren(unsigned int childCount, TrackElement* trackElem)
491{
492  if (!trackElem)
493    trackElem = this->currentTrackElem;
494
495  trackElem->childCount = childCount;
496  trackElem->mainJoin = true;  // this tells join, that this one is the Main Join, if it tries to join multiple Tracks
497  trackElem->children =  new tList<TrackElement>();
498  for (int i = 0; i < childCount; i++)
499    {
500      // create a new Element
501      TrackElement* newElem = new TrackElement();
502      // setting up the new ID
503      newElem->ID = ++trackElemCount;
504      // setting up the Time
505      newElem->startingTime = trackElem->endTime + trackElem->jumpTime;
506      // adds the conection Point
507      this->addPointV(trackElem->curve->getNode(trackElem->curve->getNodeCount()),
508                     newElem);
509      // add the new child to the childList.
510      trackElem->children->add(newElem);
511    }
512
513  // setting the Name of the new TrackElement to the name of the last one + _childI
514
515  if (trackElem->getName())
516    {
517      for (int i = 0; i < trackElem->childCount; i++)
518      {
519        char* childName = new char[strlen(trackElem->getName())+10];
520        sprintf(childName, "%s_child%d", trackElem->getName(), i);
521        trackElem->getChild(i)->setName(childName);
522      }
523    }
524  // select the first Child to work on.
525  this->currentTrackElem = trackElem->getChild(0);
526}
527
528
529/**
530   \brief Sets the trackID we are working on.
531   \param trackID the trackID we are working on
532*/
533void TrackManager::workOn(unsigned int trackID)
534{
535  TrackElement* tmpElem = this->firstTrackElem->findByID(trackID);
536  if (tmpElem)
537    this->currentTrackElem = tmpElem;
538  else
539    PRINTF(2)("TrackElement %d not Found, leaving unchanged\n", trackID);
540  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
541}
542
543/**
544   \brief Sets the TrackElement to work on
545   \param trackName the Name of the Track to work on
546*/
547void TrackManager::workOn(const char* trackName)
548{
549  TrackElement* tmpElem = this->firstTrackElem->findByName(trackName);
550  if (tmpElem)
551    this->currentTrackElem = tmpElem;
552  else
553    PRINTF(2)("TrackElement %s not Found, leaving unchanged\n", trackName);
554  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
555}
556
557/**
558   \brief Sets the Type of the Curve
559   \param curveType The Type to set
560   \param trackElem the TrackElement that should get a new Curve.
561
562   \brief this will possibly get obsolete during the process.
563*/
564void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
565{
566  if (!trackElem->isFresh)
567    {
568      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
569      return;
570    }
571  this->curveType = curveType;
572  switch (curveType)
573    {
574    case CURVE_BEZIER:
575      trackElem->curve = new BezierCurve();
576      break;
577    }
578}
579
580/**
581   \param duration the duration of the TrackElement
582   \see void TrackManager::setDuration(float duration, TrackElement* trackElem)
583*/
584void TrackManager::setDuration(float duration)
585{
586  this->setDuration(duration, NULL);
587}
588
589/**
590   \brief Sets the duration of the current path in seconds.
591   \param duration The duration in seconds.
592   \param trackElem The TrackElement to apply this to.
593*/
594void TrackManager::setDuration(float duration, TrackElement* trackElem)
595{
596  if (!trackElem)
597    trackElem = this->currentTrackElem;
598
599  trackElem->duration = duration;
600  trackElem->endTime = trackElem->startingTime + duration;
601}
602
603/**
604   \brief adds a point to trackElem
605   \param x x coord
606   \param y y coord
607   \param z z coord
608   \param trackElem The TrackElement to add the Point to
609*/
610void TrackManager::addPoint(float x, float y, float z)
611{
612  this->addPointV(Vector(x,y,z));
613}
614
615/**
616   \brief adds a point to trackElem
617   \param newPoint The point to add.
618   \param trackElem The TrackElement to add the Point to
619*/
620void TrackManager::addPointV(Vector newPoint, TrackElement* trackElem)
621{
622  if (!trackElem)
623    trackElem = this->currentTrackElem;
624
625  if (trackElem->isFresh)
626    {
627      this->setCurveType(TMAN_DEFAULT_CURVETYPE, trackElem);
628      trackElem->isFresh = false;
629    }
630  trackElem->curve->addNode(newPoint);
631  trackElem->nodeCount++;
632}
633
634/**
635   \brief adds save/splitpoint.
636   \param newPoint The point to add.
637   \param trackElem if supplied it will add a hotpoint on this TrackElement
638   \returns A Pointer to a newly appended Curve
639*/
640int TrackManager::addHotPoint(Vector newPoint, TrackElement* trackElem)
641{
642  if (!trackElem)
643    trackElem = this->currentTrackElem;
644
645  PRINTF(4)("setting up a HotPoint\n");
646  if (trackElem->isFresh)
647    {
648      trackElem->isFresh = false;
649    }
650
651  // \todo HotPoint Handling.
652  trackElem->curve->addNode(newPoint);
653  trackElem->nodeCount++;
654  this->initChildren(1, trackElem);
655}
656
657/**
658   \todo this must be better
659*/
660void TrackManager::setSavePoint(int isLoadable)
661{
662  this->setSavePoint();
663}
664
665/**
666   \brief Sets the last HotPoint into a savePoint.
667   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
668   \returns A Pointer to a newly appended Curve
669
670   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
671   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
672*/
673int TrackManager::setSavePoint(TrackElement* trackElem)
674{
675  if (!trackElem)
676    trackElem = this->currentTrackElem;
677
678  PRINTF(4)("setting up a SavePoint.\n");
679  if (trackElem->isFork || trackElem->isSavePoint)
680    {
681      PRINTF(2)("%d is already finished \n", trackElem->ID);
682      return trackElem->getChild(0)->ID;
683    }
684  trackElem->isSavePoint = true;
685  trackElem->isHotPoint = true;
686
687  this->initChildren(1, trackElem);
688}
689
690/**
691   \brief adds some interessting non-linear movments through the level.
692   \param count The Count of children the fork will produce
693
694   If no HotPoint was defined the last added Point will be rendered into a fork. \n
695   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
696*/
697void TrackManager::fork(unsigned int count, ...)
698{
699  int* trackIDs = new int[count];
700  this->forkV(count, trackIDs, NULL);
701  va_list ID;
702  va_start (ID, count);
703  for(int i = 0; i < count; i++)
704    {
705      *va_arg (ID, int*) = trackIDs[i];
706    }
707  va_end(ID); 
708  delete []trackIDs;
709}
710
711/**
712   \param count how many children to produce
713   \param ... the information on the children (these are the Stings of their names
714   \see TrackManager::fork(unsigned int count, ...)
715
716   does the same as fork, but has an array of strings as an input.
717*/
718void TrackManager::forkS(unsigned int count, ...)
719{
720  int* trackIDs = new int[count];
721  this->forkV(count, trackIDs, NULL);
722  va_list name;
723  va_start (name, count);
724  for(int i = 0; i < count; i++)
725    {
726      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
727    }
728  va_end(name); 
729  delete []trackIDs;
730}
731
732/**
733   \see TrackManager::fork(unsigned int count, ...)
734*/
735void TrackManager::forkS(const char* forkString)
736{
737  SubString strings(forkString);
738
739  int* trackIDs = new int[strings.getCount()];
740  this->forkV(strings.getCount(), trackIDs, NULL);
741
742  for(int i = 0; i < strings.getCount(); i++)
743    {
744      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
745    } 
746}
747
748/**
749   \brief adds some interessting non-linear movments through the level.
750   \param count The Count of childrens the current HotPoint will have.
751   \param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
752   \param trackNames the names for the tracks as a char-arrey-array
753   \param trackElem The TrackElement to appy this to. (if NULL choose this->currentTrackElement)
754   \see TrackManager::fork(unsigned int count, ...)
755*/
756void TrackManager::forkV(unsigned int count, int* trackIDs, char** trackNames, TrackElement* trackElem)
757{
758  if (!trackElem)
759    trackElem = this->currentTrackElem;
760
761  PRINTF(4)("Forking with %d children\n", count);
762  if (trackElem->isSavePoint)
763    return;
764  trackElem->isFork = true;
765  trackElem->isHotPoint = true;
766  for(int i = 0; i < count; i++)
767    trackIDs[i]=this->trackElemCount+1+i;
768  this->initChildren(count, trackElem);
769}
770
771/**
772   \brief decides under what condition a certain Path will be chosen.
773   \param trackID the trackID to apply this to.
774   \param cond the CONDITION of the decision
775   \param subject the Subject that will be decided upon with CONDITION cond.
776*/
777void TrackManager::condition(unsigned int trackID, CONDITION cond, void* subject)
778{
779  this->condition(cond, subject, this->firstTrackElem->findByID(trackID));
780}
781
782/**
783   \brief decides under what condition a certain Path will be chosen.
784   \param cond the CONDITION of the decision
785   \param subject the Subject that will be decided upon with CONDITION cond.
786   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
787*/
788void TrackManager::condition(CONDITION cond, void* subject, TrackElement* trackElem)
789{
790  if (!trackElem)
791    trackElem = this->currentTrackElem;
792
793  if (!trackElem->isFork)
794    {
795      PRINTF(2)("%d is not a Fork, and no condition can be set in this case\n", trackElem->ID);
796      return;
797    }
798  else
799    {
800      switch (cond)
801        {
802        case LOWEST:
803          trackElem->condFunc = &TrackElement::lowest;
804          break;
805        case HIGHEST:
806          trackElem->condFunc = &TrackElement::highest;
807          break;
808        case RANDOM: 
809          trackElem->condFunc = &TrackElement::random;
810          break;
811        case LEFTRIGHT:
812          trackElem->condFunc = &TrackElement::leftRight;
813          break;
814        case NEAREST:
815          trackElem->condFunc = &TrackElement::nearest;
816          break;
817        case ENEMYKILLED:
818          break;
819        }
820      trackElem->subject=subject;
821    }
822}
823
824/**
825   \brief joins some tracks together again.
826   \param count The count of Paths to join.
827
828   Join will set the localTime to the longest time a Path has to get to this Point. \n
829   Join will join all curves to the first curve, meaning that all the tangents will be matched.
830*/
831void TrackManager::join(unsigned int count, ...)
832{
833  int* trackIDs = new int [count];
834  va_list ID;
835  va_start (ID, count);
836  for(int i = 0; i < count; i++)
837    {
838      trackIDs[i] = va_arg (ID, int);
839    }
840  va_end(ID);
841  this->joinV(count, trackIDs);
842  delete []trackIDs;
843}
844
845/**
846   \brief Joins some Tracks together again.
847   \param count The count of trackElements to join
848   \see void TrackManager::join(unsigned int count, ...)
849
850   The difference to void TrackManager::join(unsigned int count, ...) is, that this function takes
851   the Names of the TrackElements as inputs and not their ID
852*/
853void TrackManager::joinS(unsigned int count, ...)
854{
855  int* trackIDs = new int [count];
856  va_list NAME;
857  va_start (NAME, count);
858  for(int i = 0; i < count; i++)
859    {
860      const char* name = va_arg (NAME, char*);
861      TrackElement* tmpElem = this->firstTrackElem->findByName(name);
862      if (tmpElem)
863        trackIDs[i] = tmpElem->ID;
864      else
865        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", name);
866    }
867  va_end(NAME);
868  this->joinV(count, trackIDs);
869  delete []trackIDs;
870}
871
872/**
873   \see void TrackManager::join(unsigned int count, ...)
874*/
875void TrackManager::joinS(const char* joinString)
876{
877  SubString strings(joinString);
878
879  int* trackIDs = new int[strings.getCount()];
880  this->joinV(strings.getCount(), trackIDs);
881
882  for(int i = 0; i < strings.getCount(); i++)
883    {
884      TrackElement* tmpElem = this->firstTrackElem->findByName(strings.getString(i));
885      if (tmpElem)
886        trackIDs[i] = tmpElem->ID;
887      else
888        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", strings.getString(i));
889    }
890
891  this->joinV(strings.getCount(), trackIDs);
892  delete []trackIDs;
893}
894
895/**
896   \brief joins some tracks together again.
897   \param count The count of Paths to join.
898   \param trackIDs an Array with the trackID's to join
899
900   \see void TrackManager::join(unsigned int count, ...)
901*/
902void TrackManager::joinV(unsigned int count, int* trackIDs)
903{
904  TrackElement* tmpTrackElem;
905  TrackElement* tmpJoinElem;
906  for (int i = 0; i < count; i++)
907    if (!this->firstTrackElem->findByID(trackIDs[i]))
908      {
909        PRINTF(1)("Trying to Connect Paths that do not exist yet: %d\n Not Joining Anything\n", trackIDs[i]);
910        return;
911      }
912                 
913
914  PRINTF(3)("Joining %d tracks and merging to Track %d\n", count, trackIDs[0]);
915
916  // checking if there is a back-loop-connection and ERROR if it is.
917  tmpTrackElem = this->firstTrackElem->findByID(trackIDs[0]);
918  if (!tmpTrackElem->backLoopCheck(tmpTrackElem))
919    {
920      PRINTF(2)("Backloop connection detected at joining trackElements\n -> TRACK WILL NOT BE JOINED\n");
921      return;
922    }
923
924  TrackElement* firstJoint =   this->firstTrackElem->findByID(trackIDs[0]);
925  float tmpLatestTime = firstJoint->endTime;
926
927  Vector tmpEndPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount());
928  Vector tmpTangentPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-1);
929  Vector tmpc2Point = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-2);
930  firstJoint->isJoined = true;
931  //  firstJoint->mainJoin = true;
932  if(!firstJoint->isHotPoint)
933    this->setSavePoint(firstJoint);
934  // Timing:
935  for (int i = 0; i < count; i++)
936    {
937      if(tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
938        {
939          if (tmpJoinElem->childCount == 0
940              && tmpJoinElem->endTime > tmpLatestTime)
941            tmpLatestTime = tmpJoinElem->endTime;
942        }
943    }
944  // time the main Join.
945  firstJoint->jumpTime = tmpLatestTime - firstJoint->endTime;
946 
947  // Joining:
948  for (int i = 1; i < count; i++)
949    {
950      if( tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
951        {
952          if (tmpJoinElem->childCount > 0)
953            printf("!!This Curve has children, and as such will not be joined!!\n You can try joining other childless TrackElements to this one!");
954          else
955            {
956              this->addPointV(tmpc2Point, tmpJoinElem);
957              this->addPointV(tmpTangentPoint, tmpJoinElem);
958              this->addPointV(tmpEndPoint, tmpJoinElem);
959              // time all other Joins
960              tmpJoinElem->jumpTime = tmpLatestTime - tmpJoinElem->endTime;
961             
962              //Copying Joint-Info
963              tmpJoinElem->children = firstJoint->children;
964              tmpJoinElem->childCount = firstJoint->childCount;
965              tmpJoinElem->isSavePoint = firstJoint->isSavePoint;
966              tmpJoinElem->isFork = firstJoint->isFork;
967             
968              tmpJoinElem->isJoined = true;
969            }
970        }
971    }
972  if(firstJoint->children)
973    {
974      //TrackElement* enumElem = firstJoint->children->enumerate();
975      tIterator<TrackElement>* iterator = firstJoint->children->getIterator();
976      TrackElement* enumElem = iterator->nextElement();
977      while (enumElem)
978        {
979          PRINTF(5)("Setting startingTime of %d to %f.\n", enumElem->ID, tmpLatestTime);
980          enumElem->startingTime = tmpLatestTime;
981          enumElem->endTime = tmpLatestTime + enumElem->duration;
982         
983          enumElem = iterator->nextElement();
984        }
985      delete iterator;
986    }
987}
988
989/**
990   \brief finalizes the TrackSystem. after this it will not be editable anymore
991
992   \todo check for any inconsistencies, output errors
993*/
994void TrackManager::finalize(void)
995{
996  for (int i = 1; i<= trackElemCount ;i++)
997    {
998      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
999      if( tmpElem->childCount > 0 && tmpElem->mainJoin)
1000        {
1001          tIterator<TrackElement>* iterator = tmpElem->children->getIterator();
1002          TrackElement* enumElem = iterator->nextElement();
1003          //TrackElement* enumElem = tmpElem->children->enumerate();
1004          while (enumElem)
1005            {
1006             
1007              // c1-continuity
1008              enumElem->curve->addNode(enumElem->curve->getNode(0) +
1009                                                   ((enumElem->curve->getNode(0) - 
1010                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1))
1011                                                    ),2);
1012              enumElem->nodeCount++;
1013              // c2-continuity
1014              enumElem->curve->addNode((tmpElem->curve->getNode(tmpElem->curve->getNodeCount())-
1015                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1)) * 4 +
1016                                                   tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-2), 3);
1017              enumElem->nodeCount++;                                               
1018              PRINTF(5)("accelerations: %d-in: count: %d, %f, %f, %f\n                  %d-out: count: %d %f, %f, %f\n",
1019                     tmpElem->ID, tmpElem->nodeCount,
1020                     tmpElem->curve->calcAcc(0.999).x, tmpElem->curve->calcAcc(0.999).y, tmpElem->curve->calcAcc(0.999).z,
1021                     enumElem->ID, enumElem->nodeCount,
1022                     enumElem->curve->calcAcc(0).x, enumElem->curve->calcAcc(0).y, enumElem->curve->calcAcc(0).z);
1023             
1024              enumElem = iterator->nextElement();
1025            }
1026          delete iterator;
1027        }
1028    }
1029  for (int i = 1; i <= trackElemCount;i++)
1030    if (this->firstTrackElem->findByID(i)->endTime > this->maxTime)
1031      this->maxTime = this->firstTrackElem->findByID(i)->endTime; // very bad implemented :/
1032}
1033
1034
1035// RUNTIME //
1036
1037/**
1038   \brief calculates the Position for the localTime of the Track.
1039   \returns the calculated Position
1040*/
1041Vector TrackManager::calcPos() const
1042{
1043  return this->currentTrackElem->curve->calcPos((this->localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1044}
1045
1046/**
1047   \brief calculates the Rotation for the localTime of the Track.
1048   \returns the calculated Rotation
1049*/
1050Vector TrackManager::calcDir() const
1051{
1052  return this->currentTrackElem->curve->calcDir((this->localTime - this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1053}
1054
1055/**
1056   \returns the current Width of the track
1057*/
1058float TrackManager::getWidth(void) const
1059{
1060  return this->currentTrackElem->width;
1061}
1062
1063/**
1064   \brief Advances the local-time of the Track around dt
1065   \param dt The time about which to advance.
1066
1067   This function also checks, if the TrackElement has to be changed.
1068*/
1069void TrackManager::tick(float dt)
1070{
1071  dt /= 1000;
1072  PRINTF(4)("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
1073  if (this->localTime <= this->firstTrackElem->duration)
1074    this->jumpTo(this->localTime);
1075  if (this->localTime <= this->maxTime)
1076    this->localTime += dt;
1077  if (this->localTime > this->currentTrackElem->endTime
1078      && this->currentTrackElem->children)
1079    {
1080      if (this->currentTrackElem->jumpTime != 0.0)
1081        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
1082      // jump to the next TrackElement and also set the history of the new Element to the old one.
1083      TrackElement* tmpHistoryElem = this->currentTrackElem;
1084      this->currentTrackElem = this->currentTrackElem->getChild(this->choosePath(this->currentTrackElem));
1085      this->currentTrackElem->history = tmpHistoryElem;
1086      if (this->currentTrackElem->getName())
1087        {
1088          this->trackText->setText(this->currentTrackElem->getName());
1089          this->textAnimation->replay();
1090        }
1091    }
1092  if (this->bindSlave)
1093    {
1094      Vector tmp = this->calcPos();
1095      Quaternion quat = Quaternion(this->calcDir(), Vector(this->currentTrackElem->curve->calcAcc((localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration).x,1,this->currentTrackElem->curve->calcAcc((localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration).z)); 
1096
1097      Vector v(0.0, 1.0, 0.0);
1098      Quaternion q(-PI/2, v);
1099      quat = quat * q;
1100
1101      this->bindSlave->setAbsCoor(tmp);
1102      this->bindSlave->setAbsDir(quat);
1103    }
1104}
1105
1106/**
1107   \brief Jumps to a certain point on the Track.
1108   \param time The time on the Track to jump to.
1109
1110   This should be used to Jump backwards on a Track, because moving forward means to change between the Path. (it then tries to choose the default.)
1111   Max is trackLengthMax.
1112*/
1113void TrackManager::jumpTo(float time)
1114{
1115  if (time == 0)
1116    {
1117      this->currentTrackElem = this->firstTrackElem;
1118      if (this->currentTrackElem->getName())
1119        {
1120          this->trackText->setText(this->currentTrackElem->getName());
1121          this->textAnimation->play();
1122        }
1123    }
1124  this->localTime = time;
1125}
1126
1127/**
1128   \brief a Function that decides which Path we should follow.
1129   \param trackElem The Path to choose.
1130   
1131*/
1132int TrackManager::choosePath(TrackElement* trackElem)
1133{
1134  return (trackElem->*(trackElem->condFunc))(trackElem->subject);
1135}
1136
1137/**
1138   \brief Sets the PNode, that should be moved along the Tack
1139   \param bindSlave the PNode to set
1140*/
1141void TrackManager::setBindSlave(PNode* bindSlave)
1142{
1143  this->bindSlave = bindSlave;
1144}
1145
1146/**
1147   \returns the main TrackNode
1148*/
1149PNode* TrackManager::getTrackNode(void)
1150{
1151  return this->trackNode;
1152}
1153
1154// DEBUG //
1155
1156/**
1157   \brief Imports a model of the Graph into the OpenGL-environment.
1158   \param dt The Iterator used in seconds for Painting the Graph.
1159
1160   This is for testing facility only. Do this if you want to see the Path inside the Level.
1161   eventually this will all be packed into a gl-list.
1162*/
1163void TrackManager::drawGraph(float dt) const
1164{
1165  for (int i = 1; i <= trackElemCount; i++)
1166    {
1167      glBegin(GL_LINE_STRIP);
1168      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1169      if (tmpElem->curve)
1170        for(float f = 0.0; f < 1.0; f+=dt)
1171          {
1172            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
1173            Vector tmpVector = tmpElem->curve->calcPos(f);
1174            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
1175          }
1176      glEnd();
1177    }
1178}
1179
1180/**
1181   \brief outputs debug information about the trackManager
1182   \param level how much debug
1183*/
1184void TrackManager::debug(unsigned int level) const
1185{
1186  PRINT(0)("=========================================\n");
1187  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
1188  PRINT(0)("=========================================\n");
1189  //  PRINT(0)("Status is: %
1190  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
1191  PRINT(0)(" localTime is: %f\n", this->localTime);
1192  if (level >= 2)
1193    {
1194      for (int i = 1; i <= trackElemCount; i++)
1195        {
1196          TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1197          tmpElem->debug();
1198        }
1199    }
1200  PRINT(0)("-----------------------------------------\n");
1201}
Note: See TracBrowser for help on using the repository browser.