Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/levelloader/src/track_manager.cc @ 3834

Last change on this file since 3834 was 3746, checked in by chris, 19 years ago

orxonox/branches/levelloader: Merged trunk into branch… still not working though…

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