Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: text renders as good as before, but now as Element2D

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