Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: setClassID implemented in all files

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