Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: hotpoint of TrackManager loadable

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