Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: TrackElement and Material are BaseObjects now

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