Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4318 was 4318, checked in by patrick, 19 years ago

orxonox/trunk: now changed the orxonox baseobject to object id representation. this is much faster, but needs some care, when defining new classes

File size: 34.1 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_TRACK_MANAGER
17
18#include "track_manager.h"
19
20#include "base_object.h"
21#include "p_node.h"
22#include "track_node.h"
23#include "stdincl.h"
24#include "list.h"
25#include "text_engine.h"
26#include "t_animation.h"
27#include "substring.h"
28#include "tinyxml.h"
29
30#include <stdarg.h>
31
32using namespace std;
33
34/**
35   \brief initializes a TrackElement (sets the default values)
36*/
37TrackElement::TrackElement(void)
38{
39  this->isFresh = true;
40  this->isHotPoint = false;
41  this->isSavePoint = false;
42  this->isFork = false;
43  this->isJoined = false;
44  this->mainJoin = false;
45  this->ID = -1;
46  this->startingTime = 0;
47  this->duration = TMAN_DEFAULT_DURATION;
48  this->endTime = 1;
49  this->jumpTime = 0;
50  this->width = TMAN_DEFAULT_WIDTH;
51  this->nodeCount = 0;
52  this->curve = NULL;
53  this->childCount = 0;
54  this->children = NULL;
55  this->name = NULL;
56
57  this->history = NULL;
58
59  this->subject = NULL;
60  this->condFunc = &TrackElement::random;
61}
62
63/**
64    \brief destroys all alocated memory)
65    \todo eventually when deleting a TrackElement you would not like to delete all its preceding TrackElements
66*/
67TrackElement::~TrackElement(void)
68{
69  // deleting the Name
70  delete []name;
71  // deleting the Curve
72  delete this->curve;
73
74  // deleting all the Children of this TrackNode.
75  if ((!this->isJoined &&this->childCount > 0) 
76      || (this->isJoined && this->mainJoin)) // only if this is the MainJoin.
77    {
78      tIterator<TrackElement>* iterator = this->children->getIterator();
79      TrackElement* enumElem = iterator->nextElement();
80      while (enumElem)
81        {
82          delete enumElem;
83          enumElem = iterator->nextElement();
84        }
85      delete iterator;
86      delete this->children;
87    }
88}
89
90/**
91   \brief Searches through all the TrackElements for trackID.
92   \param trackID The ID to search for.
93   \returns The TrackElement if Found, NULL otherwise.
94*/
95TrackElement* TrackElement::findByID(unsigned int trackID)
96{
97  // return if Found.
98  if (this->ID == trackID)
99    return this;
100  // search all children
101  if (this->childCount > 0)
102    {
103      tIterator<TrackElement>* iterator = this->children->getIterator();
104      TrackElement* enumElem = iterator->nextElement();
105      TrackElement* tmpElem;
106      while (enumElem)
107        {
108          if ((tmpElem = enumElem->findByID(trackID)))
109            return tmpElem;
110          enumElem = iterator->nextElement();
111        }
112      delete iterator;
113    }
114  // if not found
115  return NULL;
116}
117
118
119/**
120   \brief Searches through all the TrackElements for a trackName
121   \param trackName The name to search for.
122   \returns The TrackElement if Found, NULL otherwise.
123*/
124TrackElement* TrackElement::findByName(const char* trackName)
125{
126  // return if Found.
127  if (this->name && !strcmp(this->name, trackName))
128    return this;
129  // search all children
130  if (this->childCount > 0)
131    {
132      tIterator<TrackElement>* iterator = this->children->getIterator();
133      TrackElement* enumElem = iterator->nextElement();
134      TrackElement* tmpElem;
135      while (enumElem)
136        {
137          if ((tmpElem = enumElem->findByName(trackName)))
138            return tmpElem;
139          enumElem = iterator->nextElement();
140        }
141      delete iterator;
142    }
143  // if not found
144  return NULL;
145}
146
147/**
148   \brief checks if there are any BackLoops in the Track (Backloops only
149   \param trackElem the trackElement to check about
150   \returns true if NO loop was found, false Otherwise
151   You actually have to act on false!!
152   it simply does this by looking if the current trackElem is found again somewhere else in the Track
153*/
154bool TrackElement::backLoopCheck(const TrackElement* trackElem, unsigned int depth) const
155{
156  if(depth == 0 || this != trackElem)
157    {
158      if (this->children)
159        {
160          tIterator<TrackElement>* iterator = this->children->getIterator();
161          TrackElement* enumElem = iterator->nextElement();
162          while (enumElem)
163            {
164              if(!enumElem->backLoopCheck(trackElem, depth + 1))
165                return false;
166              enumElem = iterator->nextElement();
167            }
168          delete iterator;
169        }
170    }
171  else
172    return false;
173
174  // only returns if everything worked out
175  return true;
176}
177
178/**
179   \param childNumber which child to return
180   \returns the n-the children (starting at 0).
181   Be aware, that when the trackElement has no Children, NULL will be returned
182*/
183TrackElement* TrackElement::getChild(int childCount) const
184{
185  // if the the trackElement has no children return NULL.
186  if (this->childCount == 0)
187    return NULL;
188  // we cannot return the childCount+m's Child, so we return the last.
189  if (childCount > this->childCount)
190    childCount = this->childCount;
191 
192  tIterator<TrackElement>* iterator = this->children->getIterator();
193  TrackElement* enumElem = iterator->nextElement();
194  for (int i = 0; i < childCount; i++)
195    enumElem = iterator->nextElement();
196  delete iterator;
197  return enumElem;
198}
199
200/**
201   \param name the Name to set.
202*/
203void TrackElement::setName(const char* name)
204{
205  //  delete the old name
206  if (this->name)
207    delete []this->name;
208  // if a name was given.
209  if (name)
210    {
211      this->name = new char[strlen(name)+1];
212      strcpy(this->name, name);
213    }
214  else 
215    this->name = NULL;
216}
217
218/**
219   \returns The name of this TrackElement
220*/
221const char* TrackElement::getName(void) const
222{
223  return this->name;
224}
225
226/**
227   \brief prints out debug information about this TrackElement
228*/
229void TrackElement::debug(void) const
230{
231  PRINT(0)("--== TrackElement:%i ==--", this->ID);
232  if(this->getName())
233    PRINT(0)("--++Name: %s++--", this->getName());
234  if(this->isFresh)
235    PRINT(0)("  -- has not jet eddited in any way --\n");
236  PRINT(0)("\n   TimeTable: startingTime=%f; endTime=%f; duration=%f; jumpTime=%f\n", this->startingTime, this->endTime, this->duration, this->jumpTime);
237  PRINT(0)("   consists of %d Points\n", this->nodeCount);
238  if (this->childCount == 0)
239    PRINT(0)("   has no child\n");
240  else if (this->childCount == 1)
241    PRINT(0)("   has 1 child: =%d=\n", this->getChild(0)->ID);
242  else if (this->childCount > 1)
243    {
244      PRINT(0)("   has %d children: ", this->childCount);
245      //TrackElement* enumElem = this->children->enumerate();
246      tIterator<TrackElement>* iterator = this->children->getIterator();
247      TrackElement* enumElem = iterator->nextElement();
248      while (enumElem)
249        {
250          PRINT(0)("=%d= ", enumElem->ID);
251          enumElem = iterator->nextElement();
252        }
253      delete iterator;
254      PRINT(0)("\n");
255    }
256 
257  if(this->isHotPoint)
258    PRINT(0)("   is a special Point:\n");
259  if(this->isSavePoint)
260    PRINT(0)("    is a SavePoint\n");
261  if(this->isFork)
262    {
263      PRINT(0)("    is A Fork with with %d children.\n", this->childCount);
264    }
265  if(this->isJoined)
266    PRINT(0)("   is Joined at the End\n");
267 
268  if(!this->backLoopCheck(this)) /* this should not happen */
269    PRINT(2)(" THERE IS A BACKLOOP TO THIS ELEMENT\n");
270}
271
272/**
273   \brief CONDITION that chooses the first child for the decision (static)
274   \param nothing Nothing in this function
275   \returns the chosen child
276*/
277int TrackElement::lowest(const void* nothing) const
278{
279  return 0;
280}
281
282/**
283   \brief CONDITION that chooses the last child for the decision (static)
284   \param nothing Nothing in this function
285   \returns the chosen child
286*/
287int TrackElement::highest(const void* nothing) const
288{ 
289  return this->childCount-1;
290}
291
292/**
293   \brief CONDITION that chooses a random child for the decision (static)
294   \param nothing Nothing in this function
295   \returns the chosen child
296*/
297int TrackElement::random(const void* nothing) const
298{
299  int i = (int)floor ((float)rand()/(float)RAND_MAX * (float)this->childCount);
300  if (i >= this->childCount)
301    return this->childCount-1;
302  else 
303    return i;
304}
305
306/**
307   \brief CONDITION that chooses child 0, if the node(probably Player)
308   is left of its parent (z<0)) and 1/right otherwise.
309   \param node The node to act upon.
310   \returns the chosen child
311*/
312int TrackElement::leftRight(const void* node) const
313{
314  PNode* tmpNode = (PNode*)node;
315
316  if (tmpNode->getRelCoor().z < 0)
317    return 0;
318  else 
319    return 1;
320}
321
322
323/**
324   \brief CONDITION that chooses the child, that has the nearest distance to the node (probably player).
325   \param node The node to act upon.
326   \returns the chosen child
327
328   This is rather dangerous, because one must carefully set the points on the curve.
329   The best Way is to set the nodes as wide away of each other as possible,
330   but take into consideration, that if the nodes are to far from a center node, the center will be chosen.
331   (play with this!!).
332*/
333int TrackElement::nearest(const void* node) const
334{
335  PNode* tmpNode = (PNode*)node;
336
337  Vector nodeRelCoord = tmpNode->getRelCoor();
338  float minDist = 100000000;
339  int childNumber = 0;
340  int i = 0;
341
342  //TrackElement* enumElem = this->children->enumerate();
343  tIterator<TrackElement>* iterator = this->children->getIterator();
344  TrackElement* enumElem = iterator->nextElement();
345  while (enumElem)
346    {
347      float dist = (nodeRelCoord - enumElem->curve->getNode(4)).len();
348      if (dist < minDist)
349        {
350          minDist = dist;
351          childNumber = i;
352        }
353      i++;
354      enumElem = iterator->nextElement();
355    }
356  delete iterator;
357
358  PRINTF(4)("PathDecision with nearest algorithm: %d\n", childNumber);
359  return childNumber;
360}
361
362
363////////////////////////
364///// TRACKMANAGER /////
365////////////////////////
366/**
367   \brief standard constructor
368
369*/
370TrackManager::TrackManager(void)
371{
372  this->setClassID(CL_TRACK_MANAGER);
373 
374 
375  TrackManager::singletonRef = this; // do this because otherwise the TrackNode cannot get The instance of the TrackManager
376
377  PRINTF(3)("Initializing the TrackManager\n");
378  // setting up the First TrackElement
379  this->firstTrackElem = new TrackElement();
380  this->firstTrackElem->ID = 1;
381  this->firstTrackElem->setName("root");
382
383  this->currentTrackElem = firstTrackElem;
384
385  this->curveType = CURVE_BEZIER;
386  this->localTime = 0;
387  this->maxTime = 0;
388  this->trackElemCount = 1;
389
390  this->trackNode = new TrackNode();
391  this->setBindSlave(this->trackNode);
392  // initializing the Text
393  this->trackText = TextEngine::getInstance()->createText("fonts/earth.ttf", 30, TEXT_DYNAMIC, 0, 255, 0);
394  this->trackText->setAlignment(TEXT_ALIGN_SCREEN_CENTER);
395  // initializing the Animation for the Text.
396  this->textAnimation = new tAnimation<Text>(this->trackText, &Text::setBlending);
397  this->textAnimation->addKeyFrame(1.0, 3.0, ANIM_NEG_EXP);
398  this->textAnimation->addKeyFrame(0.0, .001);
399  this->textAnimation->setInfinity(ANIM_INF_CONSTANT);
400}
401
402
403/**
404   \brief loads a trackElement from a TiXmlElement
405   \param root the TiXmlElement to load the Data from
406*/
407bool TrackManager::load( TiXmlElement* root)
408{
409  TiXmlElement* element;
410  TiXmlNode* container;
411  double x, y, z, d;
412       
413  element = root->FirstChildElement();
414       
415  while( element != NULL)
416    {
417      if( !strcmp( element->Value(), "Point"))
418        {
419          container = element->FirstChild();
420          if( container->ToText())
421            {
422              assert( container->Value() != NULL);
423              if( sscanf( container->Value(), "%lf,%lf,%lf", &x, &y, &z) == 3)
424                {
425                  PRINTF(5)("Loaded Point: %lf,%lf,%lf (%s)\n", x, y, z, container->Value());
426                  addPoint( Vector( x, y, z));
427                }
428              else
429                {
430                  PRINTF(0)("Invalid Point in Track (skipped)\n");
431                }                       
432            }
433        }
434      else if( !strcmp( element->Value(), "Duration"))
435        {
436          container = element->FirstChild();
437          if( container->ToText())
438            {
439              assert( container->Value() != NULL);
440              if( sscanf( container->Value(), "%lf", &d) == 1)
441                {
442                  PRINTF(5)("Loaded Duration: %lf (%s)\n", d, container->Value());
443                  setDuration( d);
444                }
445              else
446                {
447                  PRINTF(2)("Invalid Duration in Track (skipped)\n");
448                }                       
449            }
450        }
451      else if( !strcmp( element->Value(), "SavePoint"))
452        {
453          PRINTF(5)("Loaded Savepoint\n");
454          setSavePoint();
455        }
456      else if( !strcmp( element->Value(), "Fork"))
457        {
458          container = element->FirstChild();
459          if( container->ToText())
460            {
461              assert( container->Value() != NULL);
462              PRINTF(4)("Loaded Fork: %s\n", container->Value());
463              forkS(container->Value());
464            }
465        }
466      else if( !strcmp( element->Value(), "Join"))
467        {
468          container = element->FirstChild();
469          if( container->ToText())
470            {
471              assert( container->Value() != NULL);
472              PRINTF0("Loaded Join: %s\n", container->Value());
473              joinS(container->Value());
474            }
475        }
476      else if( !strcmp( element->Value(), "WorkOn"))
477        {
478          container = element->FirstChild();
479          if( container->ToText())
480            {
481              assert( container->Value() != NULL);
482              PRINTF(4)("Loaded WorkOn: %s\n", container->Value());
483              workOn( container->Value());
484            }
485        }
486               
487      element = element->NextSiblingElement();
488    }
489
490}
491
492
493
494/**
495   \brief standard destructor
496*/
497TrackManager::~TrackManager(void)
498{
499  PRINTF(3)("Destruct TrackManager\n");
500
501  PRINTF(4)("Deleting all the TrackElements\n");
502  delete this->firstTrackElem;
503
504  // the tracknode should be deleted here, but is deleted by pNode: -> null_parent
505
506  // we do not have a TrackManager anymore
507  TrackManager::singletonRef = NULL;
508}
509
510//! Singleton Reference to TrackManager
511TrackManager* TrackManager::singletonRef = NULL;
512
513/**
514   \returns The reference on the TrackManager.
515
516   If the TrackManager does not exist, it will be created.
517*/
518TrackManager* TrackManager::getInstance(void) 
519{
520  if (!TrackManager::singletonRef)
521    TrackManager::singletonRef = new TrackManager();
522  return TrackManager::singletonRef;
523}
524
525
526// INITIALIZE //
527/**
528   \brief reserves Space for childCount children
529   \param childCount The Count of children to make space for.
530   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
531*/
532void TrackManager::initChildren(unsigned int childCount, TrackElement* trackElem)
533{
534  if (!trackElem)
535    trackElem = this->currentTrackElem;
536
537  trackElem->childCount = childCount;
538  trackElem->mainJoin = true;  // this tells join, that this one is the Main Join, if it tries to join multiple Tracks
539  trackElem->children =  new tList<TrackElement>();
540  for (int i = 0; i < childCount; i++)
541    {
542      // create a new Element
543      TrackElement* newElem = new TrackElement();
544      // setting up the new ID
545      newElem->ID = ++trackElemCount;
546      // setting up the Time
547      newElem->startingTime = trackElem->endTime + trackElem->jumpTime;
548      // adds the conection Point
549      this->addPoint(trackElem->curve->getNode(trackElem->curve->getNodeCount()),
550                     newElem);
551      // add the new child to the childList.
552      trackElem->children->add(newElem);
553    }
554
555  // setting the Name of the new TrackElement to the name of the last one + _childI
556
557  if (trackElem->getName())
558    {
559      for (int i = 0; i < trackElem->childCount; i++)
560      {
561        char* childName = new char[strlen(trackElem->getName())+10];
562        sprintf(childName, "%s_child%d", trackElem->getName(), i);
563        trackElem->getChild(i)->setName(childName);
564      }
565    }
566  // select the first Child to work on.
567  this->currentTrackElem = trackElem->getChild(0);
568}
569
570
571/**
572   \brief Sets the trackID we are working on.
573   \param trackID the trackID we are working on
574*/
575void TrackManager::workOn(unsigned int trackID)
576{
577  TrackElement* tmpElem = this->firstTrackElem->findByID(trackID);
578  if (tmpElem)
579    this->currentTrackElem = tmpElem;
580  else
581    PRINTF(2)("TrackElement %d not Found, leaving unchanged\n", trackID);
582  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
583}
584
585/**
586   \brief Sets the TrackElement to work on
587   \param trackName the Name of the Track to work on
588*/
589void TrackManager::workOn(const char* trackName)
590{
591  TrackElement* tmpElem = this->firstTrackElem->findByName(trackName);
592  if (tmpElem)
593    this->currentTrackElem = tmpElem;
594  else
595    PRINTF(2)("TrackElement %s not Found, leaving unchanged\n", trackName);
596  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
597}
598
599/**
600   \brief Sets the Type of the Curve
601   \param curveType The Type to set
602   \param trackElem the TrackElement that should get a new Curve.
603
604   \brief this will possibly get obsolete during the process.
605*/
606void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
607{
608  if (!trackElem->isFresh)
609    {
610      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
611      return;
612    }
613  this->curveType = curveType;
614  switch (curveType)
615    {
616    case CURVE_BEZIER:
617      trackElem->curve = new BezierCurve();
618      break;
619    }
620}
621
622/**
623   \brief Sets the duration of the current path in seconds.
624   \param duration The duration in seconds.
625   \param trackElem The TrackElement to apply this to.
626*/
627void TrackManager::setDuration(float duration, TrackElement* trackElem)
628{
629  if (!trackElem)
630    trackElem = this->currentTrackElem;
631
632  trackElem->duration = duration;
633  trackElem->endTime = trackElem->startingTime + duration;
634}
635
636/**
637   \brief adds a point to trackElem
638   \param newPoint The point to add.
639   \param trackElem The TrackElement to add the Point to
640*/
641bool TrackManager::addPoint(Vector newPoint, TrackElement* trackElem)
642{
643  if (!trackElem)
644    trackElem = this->currentTrackElem;
645
646  if (trackElem->isFresh)
647    {
648      this->setCurveType(TMAN_DEFAULT_CURVETYPE, trackElem);
649      trackElem->isFresh = false;
650    }
651  trackElem->curve->addNode(newPoint);
652  trackElem->nodeCount++;
653}
654
655/**
656   \brief adds save/splitpoint.
657   \param newPoint The point to add.
658   \returns A Pointer to a newly appended Curve
659*/
660int TrackManager::addHotPoint(Vector newPoint, TrackElement* trackElem)
661{
662  if (!trackElem)
663    trackElem = this->currentTrackElem;
664
665  PRINTF(4)("setting up a HotPoint\n");
666  if (trackElem->isFresh)
667    {
668      trackElem->isFresh = false;
669    }
670
671  // \todo HotPoint Handling.
672  trackElem->curve->addNode(newPoint);
673  trackElem->nodeCount++;
674  this->initChildren(1, trackElem);
675}
676
677/**
678   \brief Sets the last HotPoint into a savePoint.
679   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
680   \returns A Pointer to a newly appended Curve
681
682   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
683   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
684*/
685int TrackManager::setSavePoint(TrackElement* trackElem)
686{
687  if (!trackElem)
688    trackElem = this->currentTrackElem;
689
690  PRINTF(4)("setting up a SavePoint.\n");
691  if (trackElem->isFork || trackElem->isSavePoint)
692    {
693      PRINTF(2)("%d is already finished \n", trackElem->ID);
694      return trackElem->getChild(0)->ID;
695    }
696  trackElem->isSavePoint = true;
697  trackElem->isHotPoint = true;
698
699  this->initChildren(1, trackElem);
700}
701
702/**
703   \brief adds some interessting non-linear movments through the level.
704   \param count The Count of children the fork will produce
705
706   If no HotPoint was defined the last added Point will be rendered into a fork. \n
707   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
708*/
709void TrackManager::fork(unsigned int count, ...)
710{
711  int* trackIDs = new int[count];
712  this->forkV(count, trackIDs, NULL);
713  va_list ID;
714  va_start (ID, count);
715  for(int i = 0; i < count; i++)
716    {
717      *va_arg (ID, int*) = trackIDs[i];
718    }
719  va_end(ID); 
720  delete []trackIDs;
721}
722
723/**
724   \param string the String to parse.
725   \see TrackManager::fork(unsigned int count, ...)
726
727   does the same as fork, but has an array of strings as an input.
728*/
729void TrackManager::forkS(unsigned int count, ...)
730{
731  int* trackIDs = new int[count];
732  this->forkV(count, trackIDs, NULL);
733  va_list name;
734  va_start (name, count);
735  for(int i = 0; i < count; i++)
736    {
737      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
738    }
739  va_end(name); 
740  delete []trackIDs;
741}
742
743/**
744   \see TrackManager::fork(unsigned int count, ...)
745*/
746void TrackManager::forkS(const char* forkString)
747{
748  SubString strings(forkString);
749
750  int* trackIDs = new int[strings.getCount()];
751  this->forkV(strings.getCount(), trackIDs, NULL);
752
753  for(int i = 0; i < strings.getCount(); i++)
754    {
755      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
756    } 
757}
758
759/**
760   \brief adds some interessting non-linear movments through the level.
761   \param count The Count of childrens the current HotPoint will have.
762   \param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
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(tmpTrackElem))
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->addPoint(tmpc2Point, tmpJoinElem);
967              this->addPoint(tmpTangentPoint, tmpJoinElem);
968              this->addPoint(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.