Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/preferences/src/util/track/track_manager.cc @ 7246

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

orxonox/trunk: merged the std-branche back, it runs on windows and Linux

svn merge https://svn.orxonox.net/orxonox/branches/std . -r7202:HEAD

File size: 35.7 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 "util/loading/load_param.h"
22#include "p_node.h"
23#include "track_node.h"
24#include "stdincl.h"
25#include "text.h"
26#include "t_animation.h"
27
28
29#include "parser/tinyxml/tinyxml.h"
30#include "substring.h"
31
32#include <stdarg.h>
33
34using namespace std;
35
36/**
37 *  initializes a TrackElement (sets the default values)
38*/
39TrackElement::TrackElement()
40{
41  this->setClassID(CL_TRACK_ELEMENT, "TrackElement");
42
43  this->isFresh = true;
44  this->isHotPoint = false;
45  this->isSavePoint = false;
46  this->isFork = false;
47  this->isJoined = false;
48  this->mainJoin = false;
49  this->ID = -1;
50  this->startingTime = 0;
51  this->duration = TMAN_DEFAULT_DURATION;
52  this->endTime = 1;
53  this->jumpTime = 0;
54  this->width = TMAN_DEFAULT_WIDTH;
55  this->nodeCount = 0;
56  this->curve = NULL;
57  this->childCount = 0;
58  this->children = NULL;
59
60  this->history = NULL;
61
62  this->subject = NULL;
63  this->condFunc = &TrackElement::random;
64}
65
66/**
67  *  destroys all alocated memory)
68    @todo eventually when deleting a TrackElement you would not like to delete all its preceding TrackElements
69*/
70TrackElement::~TrackElement()
71{
72  // deleting the Curve
73  delete this->curve;
74
75  // deleting all the Children of this TrackNode.
76  if ((!this->isJoined &&this->childCount > 0)
77      || (this->isJoined && this->mainJoin)) // only if this is the MainJoin.
78    {
79      tIterator<TrackElement>* iterator = this->children->getIterator();
80      TrackElement* enumElem = iterator->firstElement();
81      while (enumElem)
82        {
83          delete enumElem;
84          enumElem = iterator->nextElement();
85        }
86      delete iterator;
87      delete this->children;
88    }
89}
90
91/**
92 * Searches through all the TrackElements for trackID.
93 * @param trackID The ID to search for.
94 * @returns The TrackElement if Found, NULL otherwise.
95*/
96TrackElement* TrackElement::findByID(unsigned int trackID)
97{
98  // return if Found.
99  if (this->ID == trackID)
100    return this;
101  // search all children
102  if (this->childCount > 0)
103    {
104      tIterator<TrackElement>* iterator = this->children->getIterator();
105      TrackElement* enumElem = iterator->firstElement();
106      TrackElement* tmpElem = NULL;
107      while (enumElem)
108        {
109          if ((tmpElem = enumElem->findByID(trackID)) != NULL)
110            return tmpElem;
111          enumElem = iterator->nextElement();
112        }
113      delete iterator;
114    }
115  // if not found
116  return NULL;
117}
118
119
120/**
121 *  Searches through all the TrackElements for a trackName
122 * @param trackName The name to search for.
123 * @returns The TrackElement if Found, NULL otherwise.
124*/
125TrackElement* TrackElement::findByName(const std::string& trackName)
126{
127  // return if Found.
128  if (this->getName() && !strcmp(this->getName(), trackName))
129    return this;
130  // search all children
131  if (this->childCount > 0)
132    {
133      tIterator<TrackElement>* iterator = this->children->getIterator();
134      TrackElement* enumElem = iterator->firstElement();
135      TrackElement* tmpElem;
136      while (enumElem)
137        {
138          if ((tmpElem = enumElem->findByName(trackName)))
139            return tmpElem;
140          enumElem = iterator->nextElement();
141        }
142      delete iterator;
143    }
144  // if not found
145  return NULL;
146}
147
148/**
149 *  checks if there are any BackLoops in the Track
150 * @returns true if NO loop was found, false Otherwise
151   You actually have to act on false!!
152*/
153bool TrackElement::backLoopCheck() const
154{
155  tList<const TrackElement>* trackList = new tList<const TrackElement>;
156
157  this->backLoopCheckAtomic(trackList);
158
159  delete trackList;
160  // only returns if everything worked out
161  return true;
162}
163
164/**
165 *  checks if there are any BackLoops in the Track.
166 * @param trackList A list of stored tracks, to search in.
167 * @returns true if NO loop was found, false Otherwise
168   You actually have to act on false!!
169*/
170bool TrackElement::backLoopCheckAtomic(tList<const TrackElement>* trackList) const
171{
172  if (trackList->inList(this))
173    return false;
174
175  trackList->add(this);
176
177  if (this->children)
178    {
179      tIterator<TrackElement>* iterator = this->children->getIterator();
180      TrackElement* enumElem = iterator->firstElement();
181      while (enumElem)
182        {
183          if (!enumElem->backLoopCheckAtomic(trackList))
184            return false;
185        }
186      delete iterator;
187    }
188  return true;
189}
190
191
192/**
193 * @param childCount which child to return
194 * @returns the n-the children (starting at 0).
195   Be aware, that when the trackElement has no Children, NULL will be returned
196*/
197TrackElement* TrackElement::getChild(unsigned int childCount) const
198{
199  // if the the trackElement has no children return NULL.
200  if (this->childCount == 0)
201    return NULL;
202  // we cannot return the childCount+m's Child, so we return the last.
203  if (childCount > this->childCount)
204    childCount = this->childCount;
205
206  tIterator<TrackElement>* iterator = this->children->getIterator();
207  TrackElement* enumElem = iterator->firstElement();
208  for (unsigned int i = 0; i < childCount; i++)
209    enumElem = iterator->nextElement();
210  delete iterator;
211  return enumElem;
212}
213
214/**
215 *  prints out debug information about this TrackElement
216*/
217void TrackElement::debug() const
218{
219  PRINT(0)("--== TrackElement:%i ==--", this->ID);
220  if(this->getName())
221    PRINT(0)("--++Name: %s++--", this->getName());
222  if(this->isFresh)
223    PRINT(0)("  -- has not jet eddited in any way --\n");
224  PRINT(0)("\n   TimeTable: startingTime=%f; endTime=%f; duration=%f; jumpTime=%f\n", this->startingTime, this->endTime, this->duration, this->jumpTime);
225  PRINT(0)("   consists of %d Points\n", this->nodeCount);
226  if (this->childCount == 0)
227    PRINT(0)("   has no child\n");
228  else if (this->childCount == 1)
229    PRINT(0)("   has 1 child: =%d=\n", this->getChild(0)->ID);
230  else if (this->childCount > 1)
231    {
232      PRINT(0)("   has %d children: ", this->childCount);
233      //TrackElement* enumElem = this->children->enumerate();
234      tIterator<TrackElement>* iterator = this->children->getIterator();
235      TrackElement* enumElem = iterator->firstElement();
236      while (enumElem)
237        {
238          PRINT(0)("=%d= ", enumElem->ID);
239          enumElem = iterator->nextElement();
240        }
241      delete iterator;
242      PRINT(0)("\n");
243    }
244
245  if(this->isHotPoint)
246    PRINT(0)("   is a special Point:\n");
247  if(this->isSavePoint)
248    PRINT(0)("    is a SavePoint\n");
249  if(this->isFork)
250    {
251      PRINT(0)("    is A Fork with with %d children.\n", this->childCount);
252    }
253  if(this->isJoined)
254    PRINT(0)("   is Joined at the End\n");
255
256  if(!this->backLoopCheck()) /* this should not happen */
257    PRINT(2)(" THERE IS A BACKLOOP TO THIS ELEMENT\n");
258}
259
260/**
261 *  CONDITION that chooses the first child for the decision (static)
262 * @param nothing Nothing in this function
263 * @returns the chosen child
264*/
265int TrackElement::lowest(const void* nothing) const
266{
267  return 0;
268}
269
270/**
271 *  CONDITION that chooses the last child for the decision (static)
272 * @param nothing Nothing in this function
273 * @returns the chosen child
274*/
275int TrackElement::highest(const void* nothing) const
276{
277  return this->childCount-1;
278}
279
280/**
281 *  CONDITION that chooses a random child for the decision (static)
282 * @param nothing Nothing in this function
283 * @returns the chosen child
284*/
285int TrackElement::random(const void* nothing) const
286{
287  int i = (int)floor ((float)rand()/(float)RAND_MAX * (float)this->childCount);
288  if (i >= this->childCount)
289    return this->childCount-1;
290  else
291    return i;
292}
293
294/**
295 *  CONDITION that chooses child 0, if the node(probably Player)
296   is left of its parent (z<0)) and 1/right otherwise.
297 * @param node The node to act upon.
298 * @returns the chosen child
299*/
300int TrackElement::leftRight(const void* node) const
301{
302  PNode* tmpNode = (PNode*)node;
303
304  if (tmpNode->getRelCoor().z < 0)
305    return 0;
306  else
307    return 1;
308}
309
310
311/**
312 *  CONDITION that chooses the child, that has the nearest distance to the node (probably player).
313 * @param node The node to act upon.
314 * @returns the chosen child
315
316   This is rather dangerous, because one must carefully set the points on the curve.
317   The best Way is to set the nodes as wide away of each other as possible,
318   but take into consideration, that if the nodes are to far from a center node, the center will be chosen.
319   (play with this!!).
320*/
321int TrackElement::nearest(const void* node) const
322{
323  PNode* tmpNode = (PNode*)node;
324
325  Vector nodeRelCoord = tmpNode->getRelCoor();
326  float minDist = 100000000;
327  int childNumber = 0;
328  int i = 0;
329
330  //TrackElement* enumElem = this->children->enumerate();
331  tIterator<TrackElement>* iterator = this->children->getIterator();
332  TrackElement* enumElem = iterator->firstElement();
333  while (enumElem)
334    {
335      float dist = (nodeRelCoord - enumElem->curve->getNode(4)).len();
336      if (dist < minDist)
337        {
338          minDist = dist;
339          childNumber = i;
340        }
341      i++;
342      enumElem = iterator->nextElement();
343    }
344  delete iterator;
345
346  PRINTF(4)("PathDecision with nearest algorithm: %d\n", childNumber);
347  return childNumber;
348}
349
350
351////////////////////////
352///// TRACKMANAGER /////
353////////////////////////
354/**
355 *  standard constructor
356
357*/
358TrackManager::TrackManager()
359{
360  this->setClassID(CL_TRACK_MANAGER, "TrackManager");
361  this->setName("TrackManager");
362
363  TrackManager::singletonRef = this; // do this because otherwise the TrackNode cannot get The instance of the TrackManager
364
365  PRINTF(3)("Initializing the TrackManager\n");
366  // setting up the First TrackElement
367  this->firstTrackElem = new TrackElement();
368  this->firstTrackElem->ID = 1;
369  this->firstTrackElem->setName("root");
370
371  this->currentTrackElem = firstTrackElem;
372
373  this->curveType = CURVE_BEZIER;
374  this->localTime = 0;
375  this->maxTime = 0;
376  this->trackElemCount = 1;
377
378  this->trackNode = new TrackNode();
379  this->setBindSlave(this->trackNode);
380  // initializing the Text
381  this->trackText = new Text("fonts/earth.ttf", 30);
382  this->trackText->setAlignment(E2D_ALIGN_SCREEN_CENTER);
383  // initializing the Animation for the Text.
384  this->textAnimation = new tAnimation<Text>(this->trackText, &Text::setBlending);
385  this->textAnimation->addKeyFrame(1.0, 3.0, ANIM_NEG_EXP);
386  this->textAnimation->addKeyFrame(0.0, .001);
387  this->textAnimation->setInfinity(ANIM_INF_CONSTANT);
388}
389
390
391/**
392 *  loads a trackElement from a TiXmlElement
393 * @param root the TiXmlElement to load the Data from
394*/
395void TrackManager::loadParams(const TiXmlElement* root)
396{
397  double x, y, z, d;
398
399  LOAD_PARAM_START_CYCLE(root, element);
400  {
401
402    LoadParam_CYCLE(element, "WorkOn", this, TrackManager, workOnS)
403        .describe("Selects a TrackElement (by name) to work on");
404
405    LoadParam_CYCLE(element, "Point", this, TrackManager, addPoint)
406        .describe("Adds a new Point to the currently selected TrackElement");
407
408    LoadParam_CYCLE(element, "Duration", this, TrackManager, setDuration)
409        .describe("Sets the Duration of the currently selected TrackElement");
410
411    LoadParam_CYCLE(element, "HotPoint", this, TrackManager, addHotPoint)
412        .describe("Sets a new Point that acts as a hot point. meaning, the curve will flow through this Point");
413
414    LoadParam_CYCLE(element, "SavePoint", this, TrackManager, setSavePointS)
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_CYCLE(element, "Fork", this, TrackManager, forkS)
418        .describe("Forks the Path into multiple forked Path names seperated by ','");
419
420    LoadParam_CYCLE(element, "Join", this, TrackManager, joinS)
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  }
448  LOAD_PARAM_END_CYCLE(element);
449}
450
451/**
452 *  standard destructor
453*/
454TrackManager::~TrackManager()
455{
456  PRINTF(3)("Destruct TrackManager\n");
457
458  PRINTF(4)("Deleting all the TrackElements\n");
459  delete this->firstTrackElem;
460
461  delete this->trackText;
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 *  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 *  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 *  Sets the TrackElement to work on
532 * @param trackName the Name of the Track to work on
533*/
534void TrackManager::workOnS(const std::string& 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 *  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 *  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 *  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 *  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 *  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 *  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 *  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 std::string& nextElementName)
660{
661  this->setSavePoint(NULL);
662  if (strcmp(nextElementName, ""))
663    this->firstTrackElem->findByID(this->trackElemCount)->setName(nextElementName);
664}
665
666/**
667 *  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 *  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 std::string&));
728    }
729  va_end(name);
730  delete []trackIDs;
731}
732
733/**
734   \see TrackManager::fork(unsigned int count, ...)
735*/
736void TrackManager::forkS(const std::string& 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 *  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 *  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 *  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 *  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 *  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 std::string& 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 std::string& joinString)
878{
879  SubString strings(joinString, ',');
880
881  int* trackIDs = new int[strings.getCount()];
882  this->joinV(strings.getCount(), trackIDs);
883
884  for(unsigned int i = 0; i < strings.getCount(); i++)
885    {
886      TrackElement* tmpElem = this->firstTrackElem->findByName(strings.getString(i).c_str());
887      if (tmpElem != NULL)
888        trackIDs[i] = tmpElem->ID;
889      else
890      {
891        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", strings.getString(i).c_str());
892        trackIDs[i] = -1;
893      }
894    }
895  this->joinV(strings.getCount(), trackIDs);
896  delete []trackIDs;
897}
898
899/**
900 *  joins some tracks together again.
901 * @param count The count of Paths to join.
902 * @param trackIDs an Array with the trackID's to join
903 *
904 * @see void TrackManager::join(unsigned int count, ...)
905*/
906void TrackManager::joinV(unsigned int count, int* trackIDs)
907{
908  TrackElement* tmpTrackElem;
909  TrackElement* tmpJoinElem;
910  for (unsigned int i = 0; i < count; i++)
911    if (!this->firstTrackElem->findByID(trackIDs[i]))
912      {
913        PRINTF(1)("Trying to Connect Paths that do not exist yet: %d\n Not Joining Anything\n", trackIDs[i]);
914        return;
915      }
916
917
918  PRINTF(3)("Joining %d tracks and merging to Track %d\n", count, trackIDs[0]);
919
920  // checking if there is a back-loop-connection and ERROR if it is.
921  tmpTrackElem = this->firstTrackElem->findByID(trackIDs[0]);
922  if (!tmpTrackElem->backLoopCheck())
923    {
924      PRINTF(2)("Backloop connection detected at joining trackElements\n -> TRACK WILL NOT BE JOINED\n");
925      return;
926    }
927
928  TrackElement* firstJoint =   this->firstTrackElem->findByID(trackIDs[0]);
929  float tmpLatestTime = firstJoint->endTime;
930
931  Vector tmpEndPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount());
932  Vector tmpTangentPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-1);
933  Vector tmpc2Point = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-2);
934  firstJoint->isJoined = true;
935  //  firstJoint->mainJoin = true;
936  if(!firstJoint->isHotPoint)
937    this->setSavePoint(firstJoint);
938  // Timing:
939  for (unsigned int i = 0; i < count; i++)
940    {
941      if(tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
942        {
943          if (tmpJoinElem->childCount == 0
944              && tmpJoinElem->endTime > tmpLatestTime)
945            tmpLatestTime = tmpJoinElem->endTime;
946        }
947    }
948  // time the main Join.
949  firstJoint->jumpTime = tmpLatestTime - firstJoint->endTime;
950
951  // Joining:
952  for (int i = 1; i < count; i++)
953    {
954      if( tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
955        {
956          if (tmpJoinElem->childCount > 0)
957            printf("!!This Curve has children, and as such will not be joined!!\n You can try joining other childless TrackElements to this one!");
958          else
959            {
960              this->addPointV(tmpc2Point, tmpJoinElem);
961              this->addPointV(tmpTangentPoint, tmpJoinElem);
962              this->addPointV(tmpEndPoint, tmpJoinElem);
963              // time all other Joins
964              tmpJoinElem->jumpTime = tmpLatestTime - tmpJoinElem->endTime;
965
966              //Copying Joint-Info
967              tmpJoinElem->children = firstJoint->children;
968              tmpJoinElem->childCount = firstJoint->childCount;
969              tmpJoinElem->isSavePoint = firstJoint->isSavePoint;
970              tmpJoinElem->isFork = firstJoint->isFork;
971
972              tmpJoinElem->isJoined = true;
973            }
974        }
975    }
976  if(firstJoint->children)
977    {
978      //TrackElement* enumElem = firstJoint->children->enumerate();
979      tIterator<TrackElement>* iterator = firstJoint->children->getIterator();
980      TrackElement* enumElem = iterator->firstElement();
981      while (enumElem)
982        {
983          PRINTF(5)("Setting startingTime of %d to %f.\n", enumElem->ID, tmpLatestTime);
984          enumElem->startingTime = tmpLatestTime;
985          enumElem->endTime = tmpLatestTime + enumElem->duration;
986
987          enumElem = iterator->nextElement();
988        }
989      delete iterator;
990    }
991}
992
993/**
994 *  finalizes the TrackSystem. after this it will not be editable anymore
995
996   @todo check for any inconsistencies, output errors
997*/
998void TrackManager::finalize()
999{
1000  for (int i = 1; i<= trackElemCount ;i++)
1001    {
1002      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1003      if( tmpElem->childCount > 0 && tmpElem->mainJoin)
1004        {
1005          tIterator<TrackElement>* iterator = tmpElem->children->getIterator();
1006          TrackElement* enumElem = iterator->firstElement();
1007          //TrackElement* enumElem = tmpElem->children->enumerate();
1008          while (enumElem)
1009            {
1010
1011              // c1-continuity
1012              enumElem->curve->addNode(enumElem->curve->getNode(0) +
1013                                                   ((enumElem->curve->getNode(0) -
1014                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1))
1015                                                    ),2);
1016              enumElem->nodeCount++;
1017              // c2-continuity
1018              enumElem->curve->addNode((tmpElem->curve->getNode(tmpElem->curve->getNodeCount())-
1019                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1)) * 4 +
1020                                                   tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-2), 3);
1021              enumElem->nodeCount++;
1022              PRINTF(5)("accelerations: %d-in: count: %d, %f, %f, %f\n                  %d-out: count: %d %f, %f, %f\n",
1023                     tmpElem->ID, tmpElem->nodeCount,
1024                     tmpElem->curve->calcAcc(0.999).x, tmpElem->curve->calcAcc(0.999).y, tmpElem->curve->calcAcc(0.999).z,
1025                     enumElem->ID, enumElem->nodeCount,
1026                     enumElem->curve->calcAcc(0).x, enumElem->curve->calcAcc(0).y, enumElem->curve->calcAcc(0).z);
1027
1028              enumElem = iterator->nextElement();
1029            }
1030          delete iterator;
1031        }
1032    }
1033  for (int i = 1; i <= trackElemCount;i++)
1034    if (this->firstTrackElem->findByID(i)->endTime > this->maxTime)
1035      this->maxTime = this->firstTrackElem->findByID(i)->endTime; // very bad implemented :/
1036}
1037
1038
1039// RUNTIME //
1040
1041/**
1042 *  calculates the Position for the localTime of the Track.
1043 * @returns the calculated Position
1044*/
1045Vector TrackManager::calcPos() const
1046{
1047  return this->currentTrackElem->curve->calcPos((this->localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1048}
1049
1050/**
1051 *  calculates the Rotation for the localTime of the Track.
1052 * @returns the calculated Rotation
1053*/
1054Vector TrackManager::calcDir() const
1055{
1056  return this->currentTrackElem->curve->calcDir((this->localTime - this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
1057}
1058
1059/**
1060 * @returns the current Width of the track
1061*/
1062float TrackManager::getWidth() const
1063{
1064  return this->currentTrackElem->width;
1065}
1066
1067/**
1068 *  Advances the local-time of the Track around dt
1069 * @param dt The time about which to advance.
1070
1071   This function also checks, if the TrackElement has to be changed.
1072*/
1073void TrackManager::tick(float dt)
1074{
1075  PRINTF(4)("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
1076  if (this->localTime <= this->firstTrackElem->duration)
1077    this->jumpTo(this->localTime);
1078  if (this->localTime <= this->maxTime)
1079    this->localTime += dt;
1080  if (this->localTime > this->currentTrackElem->endTime
1081      && this->currentTrackElem->children)
1082    {
1083      if (this->currentTrackElem->jumpTime != 0.0)
1084        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
1085      // jump to the next TrackElement and also set the history of the new Element to the old one.
1086      TrackElement* tmpHistoryElem = this->currentTrackElem;
1087      this->currentTrackElem = this->currentTrackElem->getChild(this->choosePath(this->currentTrackElem));
1088      this->currentTrackElem->history = tmpHistoryElem;
1089      if (this->currentTrackElem->getName())
1090        {
1091          this->trackText->setText(this->currentTrackElem->getName());
1092          this->textAnimation->replay();
1093        }
1094    }
1095  if (this->bindSlave)
1096    {
1097      Vector tmp = this->calcPos();
1098      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));
1099
1100      Vector v(0.0, 1.0, 0.0);
1101      Quaternion q(-PI/2, v);
1102      quat = quat * q;
1103
1104      this->bindSlave->setAbsCoor(tmp);
1105      this->bindSlave->setAbsDir(quat);
1106    }
1107}
1108
1109/**
1110 *  Jumps to a certain point on the Track.
1111 * @param time The time on the Track to jump to.
1112
1113   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.)
1114   Max is trackLengthMax.
1115*/
1116void TrackManager::jumpTo(float time)
1117{
1118  if (time == 0)
1119    {
1120      this->currentTrackElem = this->firstTrackElem;
1121      if (this->currentTrackElem->getName())
1122        {
1123          this->trackText->setText(this->currentTrackElem->getName());
1124          this->textAnimation->play();
1125        }
1126    }
1127  this->localTime = time;
1128}
1129
1130/**
1131 *  a Function that decides which Path we should follow.
1132 * @param trackElem The Path to choose.
1133
1134*/
1135int TrackManager::choosePath(TrackElement* trackElem)
1136{
1137  return (trackElem->*(trackElem->condFunc))(trackElem->subject);
1138}
1139
1140/**
1141 *  Sets the PNode, that should be moved along the Tack
1142 * @param bindSlave the PNode to set
1143*/
1144void TrackManager::setBindSlave(PNode* bindSlave)
1145{
1146  this->bindSlave = bindSlave;
1147}
1148
1149/**
1150 * @returns the main TrackNode
1151*/
1152PNode* TrackManager::getTrackNode()
1153{
1154  return this->trackNode;
1155}
1156
1157// DEBUG //
1158
1159/**
1160 *  Imports a model of the Graph into the OpenGL-environment.
1161 * @param dt The Iterator used in seconds for Painting the Graph.
1162
1163   This is for testing facility only. Do this if you want to see the Path inside the Level.
1164   eventually this will all be packed into a gl-list.
1165*/
1166void TrackManager::drawGraph(float dt) const
1167{
1168  for (int i = 1; i <= trackElemCount; i++)
1169    {
1170      glBegin(GL_LINE_STRIP);
1171      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1172      if (tmpElem->curve)
1173        for(float f = 0.0; f < 1.0; f+=dt)
1174          {
1175            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
1176            Vector tmpVector = tmpElem->curve->calcPos(f);
1177            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
1178          }
1179      glEnd();
1180    }
1181}
1182
1183/**
1184 *  outputs debug information about the trackManager
1185 * @param level how much debug
1186*/
1187void TrackManager::debug(unsigned int level) const
1188{
1189  PRINT(0)("=========================================\n");
1190  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
1191  PRINT(0)("=========================================\n");
1192  //  PRINT(0)("Status is: %
1193  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
1194  PRINT(0)(" localTime is: %f\n", this->localTime);
1195  if (level >= 2)
1196    {
1197      for (int i = 1; i <= trackElemCount; i++)
1198        {
1199          TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1200          tmpElem->debug();
1201        }
1202    }
1203  PRINT(0)("-----------------------------------------\n");
1204}
Note: See TracBrowser for help on using the repository browser.