Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: implemented a better backloop-check in the track-system
also implemented a new function in tList: inList() that returns tru, if a certain element is already in the List and false otherwise

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