Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: loading of track works just fine now. little problems with the setSavePoint-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->firstTrackElem->findByID(this->setSavePoint(NULL))->setName(nextElementName);
660}
661
662/**
663   \brief Sets the last HotPoint into a savePoint.
664   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
665   \returns A Pointer to a newly appended Curve
666
667   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
668   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
669*/
670int TrackManager::setSavePoint(TrackElement* trackElem)
671{
672  if (!trackElem)
673    trackElem = this->currentTrackElem;
674
675  PRINTF(4)("setting up a SavePoint.\n");
676  if (trackElem->isFork || trackElem->isSavePoint)
677    {
678      PRINTF(2)("%d is already finished \n", trackElem->ID);
679      return trackElem->getChild(0)->ID;
680    }
681  trackElem->isSavePoint = true;
682  trackElem->isHotPoint = true;
683
684  this->initChildren(1, trackElem);
685}
686
687/**
688   \brief adds some interessting non-linear movments through the level.
689   \param count The Count of children the fork will produce
690
691   If no HotPoint was defined the last added Point will be rendered into a fork. \n
692   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
693*/
694void TrackManager::fork(unsigned int count, ...)
695{
696  int* trackIDs = new int[count];
697  this->forkV(count, trackIDs, NULL);
698  va_list ID;
699  va_start (ID, count);
700  for(int i = 0; i < count; i++)
701    {
702      *va_arg (ID, int*) = trackIDs[i];
703    }
704  va_end(ID); 
705  delete []trackIDs;
706}
707
708/**
709   \param count how many children to produce
710   \param ... the information on the children (these are the Stings of their names
711   \see TrackManager::fork(unsigned int count, ...)
712
713   does the same as fork, but has an array of strings as an input.
714*/
715void TrackManager::forkS(unsigned int count, ...)
716{
717  int* trackIDs = new int[count];
718  this->forkV(count, trackIDs, NULL);
719  va_list name;
720  va_start (name, count);
721  for(int i = 0; i < count; i++)
722    {
723      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
724    }
725  va_end(name); 
726  delete []trackIDs;
727}
728
729/**
730   \see TrackManager::fork(unsigned int count, ...)
731*/
732void TrackManager::forkS(const char* forkString)
733{
734  SubString strings(forkString);
735
736  int* trackIDs = new int[strings.getCount()];
737  this->forkV(strings.getCount(), trackIDs, NULL);
738
739  for(int i = 0; i < strings.getCount(); i++)
740    {
741      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
742    } 
743  delete []trackIDs;
744}
745
746/**
747   \brief adds some interessting non-linear movments through the level.
748   \param count The Count of childrens the current HotPoint will have.
749   \param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
750   \param trackNames the names for the tracks as a char-arrey-array
751   \param trackElem The TrackElement to appy this to. (if NULL choose this->currentTrackElement)
752   \see TrackManager::fork(unsigned int count, ...)
753*/
754void TrackManager::forkV(unsigned int count, int* trackIDs, char** trackNames, TrackElement* trackElem)
755{
756  if (!trackElem)
757    trackElem = this->currentTrackElem;
758
759  PRINTF(4)("Forking with %d children\n", count);
760  if (trackElem->isSavePoint)
761    return;
762  trackElem->isFork = true;
763  trackElem->isHotPoint = true;
764  for(int i = 0; i < count; i++)
765    trackIDs[i]=this->trackElemCount+1+i;
766  this->initChildren(count, trackElem);
767}
768
769/**
770   \brief decides under what condition a certain Path will be chosen.
771   \param trackID the trackID to apply this to.
772   \param cond the CONDITION of the decision
773   \param subject the Subject that will be decided upon with CONDITION cond.
774*/
775void TrackManager::condition(unsigned int trackID, CONDITION cond, void* subject)
776{
777  this->condition(cond, subject, this->firstTrackElem->findByID(trackID));
778}
779
780/**
781   \brief decides under what condition a certain Path will be chosen.
782   \param cond the CONDITION of the decision
783   \param subject the Subject that will be decided upon with CONDITION cond.
784   \param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
785*/
786void TrackManager::condition(CONDITION cond, void* subject, TrackElement* trackElem)
787{
788  if (!trackElem)
789    trackElem = this->currentTrackElem;
790
791  if (!trackElem->isFork)
792    {
793      PRINTF(2)("%d is not a Fork, and no condition can be set in this case\n", trackElem->ID);
794      return;
795    }
796  else
797    {
798      switch (cond)
799        {
800        case LOWEST:
801          trackElem->condFunc = &TrackElement::lowest;
802          break;
803        case HIGHEST:
804          trackElem->condFunc = &TrackElement::highest;
805          break;
806        case RANDOM: 
807          trackElem->condFunc = &TrackElement::random;
808          break;
809        case LEFTRIGHT:
810          trackElem->condFunc = &TrackElement::leftRight;
811          break;
812        case NEAREST:
813          trackElem->condFunc = &TrackElement::nearest;
814          break;
815        case ENEMYKILLED:
816          break;
817        }
818      trackElem->subject=subject;
819    }
820}
821
822/**
823   \brief joins some tracks together again.
824   \param count The count of Paths to join.
825
826   Join will set the localTime to the longest time a Path has to get to this Point. \n
827   Join will join all curves to the first curve, meaning that all the tangents will be matched.
828*/
829void TrackManager::join(unsigned int count, ...)
830{
831  int* trackIDs = new int [count];
832  va_list ID;
833  va_start (ID, count);
834  for(int i = 0; i < count; i++)
835    {
836      trackIDs[i] = va_arg (ID, int);
837    }
838  va_end(ID);
839  this->joinV(count, trackIDs);
840  delete []trackIDs;
841}
842
843/**
844   \brief Joins some Tracks together again.
845   \param count The count of trackElements to join
846   \see void TrackManager::join(unsigned int count, ...)
847
848   The difference to void TrackManager::join(unsigned int count, ...) is, that this function takes
849   the Names of the TrackElements as inputs and not their ID
850*/
851void TrackManager::joinS(unsigned int count, ...)
852{
853  int* trackIDs = new int [count];
854  va_list NAME;
855  va_start (NAME, count);
856  for(int i = 0; i < count; i++)
857    {
858      const char* name = va_arg (NAME, char*);
859      TrackElement* tmpElem = this->firstTrackElem->findByName(name);
860      if (tmpElem)
861        trackIDs[i] = tmpElem->ID;
862      else
863        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", name);
864    }
865  va_end(NAME);
866  this->joinV(count, trackIDs);
867  delete []trackIDs;
868}
869
870/**
871   \see void TrackManager::join(unsigned int count, ...)
872*/
873void TrackManager::joinS(const char* joinString)
874{
875  SubString strings(joinString);
876
877  int* trackIDs = new int[strings.getCount()];
878  this->joinV(strings.getCount(), trackIDs);
879
880  for(int i = 0; i < strings.getCount(); i++)
881    {
882      TrackElement* tmpElem = this->firstTrackElem->findByName(strings.getString(i));
883      if (tmpElem)
884        trackIDs[i] = tmpElem->ID;
885      else
886        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", strings.getString(i));
887    }
888
889  this->joinV(strings.getCount(), trackIDs);
890  delete []trackIDs;
891}
892
893/**
894   \brief joins some tracks together again.
895   \param count The count of Paths to join.
896   \param trackIDs an Array with the trackID's to join
897
898   \see void TrackManager::join(unsigned int count, ...)
899*/
900void TrackManager::joinV(unsigned int count, int* trackIDs)
901{
902  TrackElement* tmpTrackElem;
903  TrackElement* tmpJoinElem;
904  for (int i = 0; i < count; i++)
905    if (!this->firstTrackElem->findByID(trackIDs[i]))
906      {
907        PRINTF(1)("Trying to Connect Paths that do not exist yet: %d\n Not Joining Anything\n", trackIDs[i]);
908        return;
909      }
910                 
911
912  PRINTF(3)("Joining %d tracks and merging to Track %d\n", count, trackIDs[0]);
913
914  // checking if there is a back-loop-connection and ERROR if it is.
915  tmpTrackElem = this->firstTrackElem->findByID(trackIDs[0]);
916  if (!tmpTrackElem->backLoopCheck(tmpTrackElem))
917    {
918      PRINTF(2)("Backloop connection detected at joining trackElements\n -> TRACK WILL NOT BE JOINED\n");
919      return;
920    }
921
922  TrackElement* firstJoint =   this->firstTrackElem->findByID(trackIDs[0]);
923  float tmpLatestTime = firstJoint->endTime;
924
925  Vector tmpEndPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount());
926  Vector tmpTangentPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-1);
927  Vector tmpc2Point = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-2);
928  firstJoint->isJoined = true;
929  //  firstJoint->mainJoin = true;
930  if(!firstJoint->isHotPoint)
931    this->setSavePoint(firstJoint);
932  // Timing:
933  for (int i = 0; i < count; i++)
934    {
935      if(tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
936        {
937          if (tmpJoinElem->childCount == 0
938              && tmpJoinElem->endTime > tmpLatestTime)
939            tmpLatestTime = tmpJoinElem->endTime;
940        }
941    }
942  // time the main Join.
943  firstJoint->jumpTime = tmpLatestTime - firstJoint->endTime;
944 
945  // Joining:
946  for (int i = 1; i < count; i++)
947    {
948      if( tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
949        {
950          if (tmpJoinElem->childCount > 0)
951            printf("!!This Curve has children, and as such will not be joined!!\n You can try joining other childless TrackElements to this one!");
952          else
953            {
954              this->addPointV(tmpc2Point, tmpJoinElem);
955              this->addPointV(tmpTangentPoint, tmpJoinElem);
956              this->addPointV(tmpEndPoint, tmpJoinElem);
957              // time all other Joins
958              tmpJoinElem->jumpTime = tmpLatestTime - tmpJoinElem->endTime;
959             
960              //Copying Joint-Info
961              tmpJoinElem->children = firstJoint->children;
962              tmpJoinElem->childCount = firstJoint->childCount;
963              tmpJoinElem->isSavePoint = firstJoint->isSavePoint;
964              tmpJoinElem->isFork = firstJoint->isFork;
965             
966              tmpJoinElem->isJoined = true;
967            }
968        }
969    }
970  if(firstJoint->children)
971    {
972      //TrackElement* enumElem = firstJoint->children->enumerate();
973      tIterator<TrackElement>* iterator = firstJoint->children->getIterator();
974      TrackElement* enumElem = iterator->nextElement();
975      while (enumElem)
976        {
977          PRINTF(5)("Setting startingTime of %d to %f.\n", enumElem->ID, tmpLatestTime);
978          enumElem->startingTime = tmpLatestTime;
979          enumElem->endTime = tmpLatestTime + enumElem->duration;
980         
981          enumElem = iterator->nextElement();
982        }
983      delete iterator;
984    }
985}
986
987/**
988   \brief finalizes the TrackSystem. after this it will not be editable anymore
989
990   \todo check for any inconsistencies, output errors
991*/
992void TrackManager::finalize(void)
993{
994  for (int i = 1; i<= trackElemCount ;i++)
995    {
996      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
997      if( tmpElem->childCount > 0 && tmpElem->mainJoin)
998        {
999          tIterator<TrackElement>* iterator = tmpElem->children->getIterator();
1000          TrackElement* enumElem = iterator->nextElement();
1001          //TrackElement* enumElem = tmpElem->children->enumerate();
1002          while (enumElem)
1003            {
1004             
1005              // c1-continuity
1006              enumElem->curve->addNode(enumElem->curve->getNode(0) +
1007                                                   ((enumElem->curve->getNode(0) - 
1008                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1))
1009                                                    ),2);
1010              enumElem->nodeCount++;
1011              // c2-continuity
1012              enumElem->curve->addNode((tmpElem->curve->getNode(tmpElem->curve->getNodeCount())-
1013                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1)) * 4 +
1014                                                   tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-2), 3);
1015              enumElem->nodeCount++;                                               
1016              PRINTF(5)("accelerations: %d-in: count: %d, %f, %f, %f\n                  %d-out: count: %d %f, %f, %f\n",
1017                     tmpElem->ID, tmpElem->nodeCount,
1018                     tmpElem->curve->calcAcc(0.999).x, tmpElem->curve->calcAcc(0.999).y, tmpElem->curve->calcAcc(0.999).z,
1019                     enumElem->ID, enumElem->nodeCount,
1020                     enumElem->curve->calcAcc(0).x, enumElem->curve->calcAcc(0).y, enumElem->curve->calcAcc(0).z);
1021             
1022              enumElem = iterator->nextElement();
1023            }
1024          delete iterator;
1025        }
1026    }
1027  for (int i = 1; i <= trackElemCount;i++)
1028    if (this->firstTrackElem->findByID(i)->endTime > this->maxTime)
1029      this->maxTime = this->firstTrackElem->findByID(i)->endTime; // very bad implemented :/
1030}
1031
1032
1033// RUNTIME //
1034
1035/**
1036   \brief calculates the Position for the localTime of the Track.
1037   \returns the calculated Position
1038*/
1039Vector TrackManager::calcPos() const
1040{
1041  return this->currentTrackElem->curve->calcPos((this->localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1042}
1043
1044/**
1045   \brief calculates the Rotation for the localTime of the Track.
1046   \returns the calculated Rotation
1047*/
1048Vector TrackManager::calcDir() const
1049{
1050  return this->currentTrackElem->curve->calcDir((this->localTime - this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1051}
1052
1053/**
1054   \returns the current Width of the track
1055*/
1056float TrackManager::getWidth(void) const
1057{
1058  return this->currentTrackElem->width;
1059}
1060
1061/**
1062   \brief Advances the local-time of the Track around dt
1063   \param dt The time about which to advance.
1064
1065   This function also checks, if the TrackElement has to be changed.
1066*/
1067void TrackManager::tick(float dt)
1068{
1069  dt /= 1000;
1070  PRINTF(4)("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
1071  if (this->localTime <= this->firstTrackElem->duration)
1072    this->jumpTo(this->localTime);
1073  if (this->localTime <= this->maxTime)
1074    this->localTime += dt;
1075  if (this->localTime > this->currentTrackElem->endTime
1076      && this->currentTrackElem->children)
1077    {
1078      if (this->currentTrackElem->jumpTime != 0.0)
1079        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
1080      // jump to the next TrackElement and also set the history of the new Element to the old one.
1081      TrackElement* tmpHistoryElem = this->currentTrackElem;
1082      this->currentTrackElem = this->currentTrackElem->getChild(this->choosePath(this->currentTrackElem));
1083      this->currentTrackElem->history = tmpHistoryElem;
1084      if (this->currentTrackElem->getName())
1085        {
1086          this->trackText->setText(this->currentTrackElem->getName());
1087          this->textAnimation->replay();
1088        }
1089    }
1090  if (this->bindSlave)
1091    {
1092      Vector tmp = this->calcPos();
1093      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)); 
1094
1095      Vector v(0.0, 1.0, 0.0);
1096      Quaternion q(-PI/2, v);
1097      quat = quat * q;
1098
1099      this->bindSlave->setAbsCoor(tmp);
1100      this->bindSlave->setAbsDir(quat);
1101    }
1102}
1103
1104/**
1105   \brief Jumps to a certain point on the Track.
1106   \param time The time on the Track to jump to.
1107
1108   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.)
1109   Max is trackLengthMax.
1110*/
1111void TrackManager::jumpTo(float time)
1112{
1113  if (time == 0)
1114    {
1115      this->currentTrackElem = this->firstTrackElem;
1116      if (this->currentTrackElem->getName())
1117        {
1118          this->trackText->setText(this->currentTrackElem->getName());
1119          this->textAnimation->play();
1120        }
1121    }
1122  this->localTime = time;
1123}
1124
1125/**
1126   \brief a Function that decides which Path we should follow.
1127   \param trackElem The Path to choose.
1128   
1129*/
1130int TrackManager::choosePath(TrackElement* trackElem)
1131{
1132  return (trackElem->*(trackElem->condFunc))(trackElem->subject);
1133}
1134
1135/**
1136   \brief Sets the PNode, that should be moved along the Tack
1137   \param bindSlave the PNode to set
1138*/
1139void TrackManager::setBindSlave(PNode* bindSlave)
1140{
1141  this->bindSlave = bindSlave;
1142}
1143
1144/**
1145   \returns the main TrackNode
1146*/
1147PNode* TrackManager::getTrackNode(void)
1148{
1149  return this->trackNode;
1150}
1151
1152// DEBUG //
1153
1154/**
1155   \brief Imports a model of the Graph into the OpenGL-environment.
1156   \param dt The Iterator used in seconds for Painting the Graph.
1157
1158   This is for testing facility only. Do this if you want to see the Path inside the Level.
1159   eventually this will all be packed into a gl-list.
1160*/
1161void TrackManager::drawGraph(float dt) const
1162{
1163  for (int i = 1; i <= trackElemCount; i++)
1164    {
1165      glBegin(GL_LINE_STRIP);
1166      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1167      if (tmpElem->curve)
1168        for(float f = 0.0; f < 1.0; f+=dt)
1169          {
1170            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
1171            Vector tmpVector = tmpElem->curve->calcPos(f);
1172            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
1173          }
1174      glEnd();
1175    }
1176}
1177
1178/**
1179   \brief outputs debug information about the trackManager
1180   \param level how much debug
1181*/
1182void TrackManager::debug(unsigned int level) const
1183{
1184  PRINT(0)("=========================================\n");
1185  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
1186  PRINT(0)("=========================================\n");
1187  //  PRINT(0)("Status is: %
1188  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
1189  PRINT(0)(" localTime is: %f\n", this->localTime);
1190  if (level >= 2)
1191    {
1192      for (int i = 1; i <= trackElemCount; i++)
1193        {
1194          TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1195          tmpElem->debug();
1196        }
1197    }
1198  PRINT(0)("-----------------------------------------\n");
1199}
Note: See TracBrowser for help on using the repository browser.