Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: track: doxy-tags, redesign, and minor speed-update

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