Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fixed the bug with the setSavePointS()-function

File size: 34.5 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       
413  while( element != NULL)
414    {
415      LoadParam<TrackManager>(element, "WorkOn", this, &TrackManager::workOnS, true)
416        .describe("Selects a TrackElement (by name) to work on");
417
418      LoadParam<TrackManager>(element, "Point", this, &TrackManager::addPoint, true)
419        .describe("Adds a new Point to the currently selected TrackElement");
420
421      LoadParam<TrackManager>(element, "Duration", this, &TrackManager::setDuration, true)
422        .describe("Sets the Duration of the currently selected TrackElement");
423     
424      LoadParam<TrackManager>(element, "SavePoint", this, &TrackManager::setSavePointS, true)
425        .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");
426
427      LoadParam<TrackManager>(element, "Fork", this, &TrackManager::forkS, true)
428        .describe("Forks the Path into multiple forked Path names seperated by ','");
429
430      LoadParam<TrackManager>(element, "Join", this, &TrackManager::joinS, true)
431        .describe("Joins multiple joining Path names seperated by ','");
432
433      /*
434        if( !strcmp( element->Value(), "Fork"))
435        {
436        container = element->FirstChild();
437        if( container->ToText())
438        {
439        assert( container->Value() != NULL);
440        PRINTF(4)("Loaded Fork: %s\n", container->Value());
441        forkS(container->Value());
442        }
443        }
444      */
445      /*
446        if( !strcmp( element->Value(), "Join"))
447        {
448        container = element->FirstChild();
449        if( container->ToText())
450        {
451        assert( container->Value() != NULL);
452        PRINTF0("Loaded Join: %s\n", container->Value());
453        joinS(container->Value());
454        }
455        }
456      */       
457      element = element->NextSiblingElement();
458    }
459
460}
461
462/**
463   \brief standard destructor
464*/
465TrackManager::~TrackManager(void)
466{
467  PRINTF(3)("Destruct TrackManager\n");
468
469  PRINTF(4)("Deleting all the TrackElements\n");
470  delete this->firstTrackElem;
471
472  // the tracknode should be deleted here, but is deleted by pNode: -> null_parent
473
474  // we do not have a TrackManager anymore
475  TrackManager::singletonRef = NULL;
476}
477
478//! Singleton Reference to TrackManager
479TrackManager* TrackManager::singletonRef = NULL;
480
481// INITIALIZE //
482/**
483   \brief reserves Space for childCount children
484   \param childCount The Count of children to make space for.
485   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
486*/
487void TrackManager::initChildren(unsigned int childCount, TrackElement* trackElem)
488{
489  if (!trackElem)
490    trackElem = this->currentTrackElem;
491
492  trackElem->childCount = childCount;
493  trackElem->mainJoin = true;  // this tells join, that this one is the Main Join, if it tries to join multiple Tracks
494  trackElem->children =  new tList<TrackElement>();
495  for (int i = 0; i < childCount; i++)
496    {
497      // create a new Element
498      TrackElement* newElem = new TrackElement();
499      // setting up the new ID
500      newElem->ID = ++trackElemCount;
501      // setting up the Time
502      newElem->startingTime = trackElem->endTime + trackElem->jumpTime;
503      // adds the conection Point
504      this->addPointV(trackElem->curve->getNode(trackElem->curve->getNodeCount()),
505                     newElem);
506      // add the new child to the childList.
507      trackElem->children->add(newElem);
508    }
509
510  // setting the Name of the new TrackElement to the name of the last one + _childI
511
512  if (trackElem->getName())
513    {
514      for (int i = 0; i < trackElem->childCount; i++)
515      {
516        char* childName = new char[strlen(trackElem->getName())+10];
517        sprintf(childName, "%s_child%d", trackElem->getName(), i);
518        trackElem->getChild(i)->setName(childName);
519      }
520    }
521  // select the first Child to work on.
522  this->currentTrackElem = trackElem->getChild(0);
523}
524
525
526/**
527   \brief Sets the trackID we are working on.
528   \param trackID the trackID we are working on
529*/
530void TrackManager::workOn(unsigned int trackID)
531{
532  TrackElement* tmpElem = this->firstTrackElem->findByID(trackID);
533  if (tmpElem)
534    this->currentTrackElem = tmpElem;
535  else
536    PRINTF(2)("TrackElement %d not Found, leaving unchanged\n", trackID);
537  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
538}
539
540/**
541   \brief Sets the TrackElement to work on
542   \param trackName the Name of the Track to work on
543*/
544void TrackManager::workOnS(const char* trackName)
545{
546  TrackElement* tmpElem = this->firstTrackElem->findByName(trackName);
547  if (tmpElem)
548    this->currentTrackElem = tmpElem;
549  else
550    PRINTF(2)("TrackElement %s not Found, leaving unchanged\n", trackName);
551  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
552}
553
554/**
555   \brief Sets the Type of the Curve
556   \param curveType The Type to set
557   \param trackElem the TrackElement that should get a new Curve.
558
559   \brief this will possibly get obsolete during the process.
560*/
561void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
562{
563  if (!trackElem->isFresh)
564    {
565      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
566      return;
567    }
568  this->curveType = curveType;
569  switch (curveType)
570    {
571    case CURVE_BEZIER:
572      trackElem->curve = new BezierCurve();
573      break;
574    }
575}
576
577/**
578   \param duration the duration of the TrackElement
579   \see void TrackManager::setDuration(float duration, TrackElement* trackElem)
580*/
581void TrackManager::setDuration(float duration)
582{
583  this->setDuration(duration, NULL);
584}
585
586/**
587   \brief Sets the duration of the current path in seconds.
588   \param duration The duration in seconds.
589   \param trackElem The TrackElement to apply this to.
590*/
591void TrackManager::setDuration(float duration, TrackElement* trackElem)
592{
593  if (!trackElem)
594    trackElem = this->currentTrackElem;
595
596  trackElem->duration = duration;
597  trackElem->endTime = trackElem->startingTime + duration;
598}
599
600/**
601   \brief adds a point to trackElem
602   \param x x coord
603   \param y y coord
604   \param z z coord
605   \param trackElem The TrackElement to add the Point to
606*/
607void TrackManager::addPoint(float x, float y, float z)
608{
609  this->addPointV(Vector(x,y,z));
610}
611
612/**
613   \brief adds a point to trackElem
614   \param newPoint The point to add.
615   \param trackElem The TrackElement to add the Point to
616*/
617void TrackManager::addPointV(Vector newPoint, TrackElement* trackElem)
618{
619  if (!trackElem)
620    trackElem = this->currentTrackElem;
621
622  if (trackElem->isFresh)
623    {
624      this->setCurveType(TMAN_DEFAULT_CURVETYPE, trackElem);
625      trackElem->isFresh = false;
626    }
627  trackElem->curve->addNode(newPoint);
628  trackElem->nodeCount++;
629}
630
631/**
632   \brief adds save/splitpoint.
633   \param newPoint The point to add.
634   \param trackElem if supplied it will add a hotpoint on this TrackElement
635   \returns A Pointer to a newly appended Curve
636*/
637int TrackManager::addHotPoint(Vector newPoint, TrackElement* trackElem)
638{
639  if (!trackElem)
640    trackElem = this->currentTrackElem;
641
642  PRINTF(4)("setting up a HotPoint\n");
643  if (trackElem->isFresh)
644    {
645      trackElem->isFresh = false;
646    }
647
648  // \todo HotPoint Handling.
649  trackElem->curve->addNode(newPoint);
650  trackElem->nodeCount++;
651  this->initChildren(1, trackElem);
652}
653
654/**
655   \todo this must be better
656*/
657void TrackManager::setSavePointS(const char* nextElementName)
658{
659  this->setSavePoint(NULL);
660  if (strcmp(nextElementName, ""))
661    this->firstTrackElem->findByID(this->trackElemCount)->setName(nextElementName);
662}
663
664/**
665   \brief Sets the last HotPoint into a savePoint.
666   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
667   \returns A Pointer to a newly appended Curve
668
669   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
670   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
671*/
672void TrackManager::setSavePoint(TrackElement* trackElem)
673{
674  if (!trackElem)
675    trackElem = this->currentTrackElem;
676
677  PRINTF(4)("setting up a SavePoint.\n");
678  if (trackElem->isFork || trackElem->isSavePoint)
679    {
680      PRINTF(2)("%d is already finished \n", trackElem->ID);
681      return;
682    }
683  trackElem->isSavePoint = true;
684  trackElem->isHotPoint = true;
685
686  this->initChildren(1, trackElem);
687}
688
689/**
690   \brief adds some interessting non-linear movments through the level.
691   \param count The Count of children the fork will produce
692
693   If no HotPoint was defined the last added Point will be rendered into a fork. \n
694   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
695*/
696void TrackManager::fork(unsigned int count, ...)
697{
698  int* trackIDs = new int[count];
699  this->forkV(count, trackIDs, NULL);
700  va_list ID;
701  va_start (ID, count);
702  for(int i = 0; i < count; i++)
703    {
704      *va_arg (ID, int*) = trackIDs[i];
705    }
706  va_end(ID); 
707  delete []trackIDs;
708}
709
710/**
711   \param count how many children to produce
712   \param ... the information on the children (these are the Stings of their names
713   \see TrackManager::fork(unsigned int count, ...)
714
715   does the same as fork, but has an array of strings as an input.
716*/
717void TrackManager::forkS(unsigned int count, ...)
718{
719  int* trackIDs = new int[count];
720  this->forkV(count, trackIDs, NULL);
721  va_list name;
722  va_start (name, count);
723  for(int i = 0; i < count; i++)
724    {
725      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
726    }
727  va_end(name); 
728  delete []trackIDs;
729}
730
731/**
732   \see TrackManager::fork(unsigned int count, ...)
733*/
734void TrackManager::forkS(const char* forkString)
735{
736  SubString strings(forkString);
737
738  int* trackIDs = new int[strings.getCount()];
739  this->forkV(strings.getCount(), trackIDs, NULL);
740
741  for(int i = 0; i < strings.getCount(); i++)
742    {
743      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
744    } 
745  delete []trackIDs;
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.