Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/track_manager.cc @ 4251

Last change on this file since 4251 was 4220, checked in by bensch, 20 years ago

orxonox/trunk: TrackManager prepared for loading. added new overloaded functions that read in join and fork from one single string
thanks to chris, this was pretty easy… the hard part was finding the substring class :)

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