Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10435 was 10368, checked in by patrick, 18 years ago

merged the branche playability into the trunk

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