Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4488 was 4320, checked in by patrick, 20 years ago

orxonox/trunk: now string name of a class works parallel to the int id representation and is only used for documentation purposes

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