Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ini-parser in own subdir now (also moved tiXml-lib to lib/parser

File size: 35.7 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"
[5129]21#include "load_param.h"
[3433]22#include "p_node.h"
[3528]23#include "track_node.h"
[3608]24#include "stdincl.h"
25#include "list.h"
[5344]26#include "text.h"
[3849]27#include "t_animation.h"
[4496]28
29
[5944]30#include "parser/tinyxml/tinyxml.h"
[4220]31#include "substring.h"
[3528]32
[3495]33#include <stdarg.h>
34
[3311]35using namespace std;
36
[3331]37/**
[4836]38 *  initializes a TrackElement (sets the default values)
[3331]39*/
[4746]40TrackElement::TrackElement()
[3331]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/**
[4836]68  *  destroys all alocated memory)
69    @todo eventually when deleting a TrackElement you would not like to delete all its preceding TrackElements
[3331]70*/
[4746]71TrackElement::~TrackElement()
[3331]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();
[5115]81      TrackElement* enumElem = iterator->firstElement();
[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/**
[5336]93 * Searches through all the TrackElements for trackID.
[4836]94 * @param trackID The ID to search for.
95 * @returns The TrackElement if Found, NULL otherwise.
[3332]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();
[5115]106      TrackElement* enumElem = iterator->firstElement();
[5313]107      TrackElement* tmpElem = NULL;
[3594]108      while (enumElem)
[4584]109        {
[5313]110          if ((tmpElem = enumElem->findByID(trackID)) != NULL)
[4584]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/**
[4836]122 *  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();
[5115]135      TrackElement* enumElem = iterator->firstElement();
[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/**
[4836]150 *  checks if there are any BackLoops in the Track
151 * @returns true if NO loop was found, false Otherwise
[3835]152   You actually have to act on false!!
[4508]153*/
[4746]154bool TrackElement::backLoopCheck() const
[4508]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/**
[4836]166 *  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
[4508]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();
[5115]181      TrackElement* enumElem = iterator->firstElement();
[4508]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/**
[4836]194 * @param childCount which child to return
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*/
[5313]198TrackElement* TrackElement::getChild(unsigned 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();
[5115]208  TrackElement* enumElem = iterator->firstElement();
[5313]209  for (unsigned int i = 0; i < childCount; i++)
[3832]210    enumElem = iterator->nextElement();
211  delete iterator;
[3594]212  return enumElem;
213}
214
215/**
[4836]216 *  prints out debug information about this TrackElement
[3593]217*/
[4746]218void TrackElement::debug() 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();
[5115]236      TrackElement* enumElem = iterator->firstElement();
[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/**
[4836]262 *  CONDITION that chooses the first child for the decision (static)
263 * @param nothing Nothing in this function
264 * @returns the chosen child
[3522]265*/
[3835]266int TrackElement::lowest(const void* nothing) const
[3522]267{
268  return 0;
269}
[3332]270
[3522]271/**
[4836]272 *  CONDITION that chooses the last child for the decision (static)
273 * @param nothing Nothing in this function
274 * @returns the chosen child
[3522]275*/
[3835]276int TrackElement::highest(const void* nothing) const
[4584]277{
[3522]278  return this->childCount-1;
279}
[3332]280
[3522]281/**
[4836]282 *  CONDITION that chooses a random child for the decision (static)
283 * @param nothing Nothing in this function
284 * @returns the chosen child
[3522]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/**
[4836]296 *  CONDITION that chooses child 0, if the node(probably Player)
[3522]297   is left of its parent (z<0)) and 1/right otherwise.
[4836]298 * @param node The node to act upon.
299 * @returns the chosen child
[3522]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/**
[4836]313 *  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
[3522]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();
[5115]333  TrackElement* enumElem = iterator->firstElement();
[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/**
[4836]356 *  standard constructor
[3311]357
358*/
[4746]359TrackManager::TrackManager()
[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
[5767]382  this->trackText = new Text("fonts/earth.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*/
[4834]396bool TrackManager::loadParams(const TiXmlElement* root)
[4017]397{
[4220]398  double x, y, z, d;
[4584]399
[5654]400  LOAD_PARAM_START_CYCLE(root, element);
401  {
[4834]402
[5654]403    LoadParam_CYCLE(element, "WorkOn", this, TrackManager, workOnS)
[4584]404        .describe("Selects a TrackElement (by name) to work on");
[4501]405
[5654]406    LoadParam_CYCLE(element, "Point", this, TrackManager, addPoint)
[4584]407        .describe("Adds a new Point to the currently selected TrackElement");
[4496]408
[5654]409    LoadParam_CYCLE(element, "Duration", this, TrackManager, setDuration)
[4584]410        .describe("Sets the Duration of the currently selected TrackElement");
[4509]411
[5654]412    LoadParam_CYCLE(element, "HotPoint", this, TrackManager, addHotPoint)
[4584]413        .describe("Sets a new Point that acts as a hot point. meaning, the curve will flow through this Point");
414
[5654]415    LoadParam_CYCLE(element, "SavePoint", this, TrackManager, setSavePointS)
[4584]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");
[4496]417
[5654]418    LoadParam_CYCLE(element, "Fork", this, TrackManager, forkS)
[4584]419        .describe("Forks the Path into multiple forked Path names seperated by ','");
[4501]420
[5654]421    LoadParam_CYCLE(element, "Join", this, TrackManager, joinS)
[4584]422        .describe("Joins multiple joining Path names seperated by ','");
[4501]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      */
[5654]448  }
449  LOAD_PARAM_END_CYCLE(element);
[4017]450}
451
452/**
[4836]453 *  standard destructor
[3311]454*/
[4746]455TrackManager::~TrackManager()
[3330]456{
[3331]457  PRINTF(3)("Destruct TrackManager\n");
[3311]458
[3594]459  PRINTF(4)("Deleting all the TrackElements\n");
[3331]460  delete this->firstTrackElem;
[3335]461
[5079]462  delete this->trackText;
[3836]463  // the tracknode should be deleted here, but is deleted by pNode: -> null_parent
464
[3331]465  // we do not have a TrackManager anymore
[3594]466  TrackManager::singletonRef = NULL;
[3330]467}
468
[3543]469//! Singleton Reference to TrackManager
[3331]470TrackManager* TrackManager::singletonRef = NULL;
471
[3836]472// INITIALIZE //
[3331]473/**
[4836]474 *  reserves Space for childCount children
475 * @param childCount The Count of children to make space for.
476 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
[3335]477*/
[3836]478void TrackManager::initChildren(unsigned int childCount, TrackElement* trackElem)
[3335]479{
[3836]480  if (!trackElem)
481    trackElem = this->currentTrackElem;
482
483  trackElem->childCount = childCount;
484  trackElem->mainJoin = true;  // this tells join, that this one is the Main Join, if it tries to join multiple Tracks
485  trackElem->children =  new tList<TrackElement>();
[3594]486  for (int i = 0; i < childCount; i++)
[3348]487    {
[3836]488      // create a new Element
[3594]489      TrackElement* newElem = new TrackElement();
[3836]490      // setting up the new ID
[3594]491      newElem->ID = ++trackElemCount;
[3836]492      // setting up the Time
493      newElem->startingTime = trackElem->endTime + trackElem->jumpTime;
494      // adds the conection Point
[4496]495      this->addPointV(trackElem->curve->getNode(trackElem->curve->getNodeCount()),
[4584]496                     newElem);
[3836]497      // add the new child to the childList.
498      trackElem->children->add(newElem);
[3348]499    }
[3836]500
[3842]501  // setting the Name of the new TrackElement to the name of the last one + _childI
[3837]502
[3842]503  if (trackElem->getName())
504    {
505      for (int i = 0; i < trackElem->childCount; i++)
506      {
[4584]507        char* childName = new char[strlen(trackElem->getName())+10];
508        sprintf(childName, "%s_child%d", trackElem->getName(), i);
509        trackElem->getChild(i)->setName(childName);
[3842]510      }
511    }
[3837]512  // select the first Child to work on.
513  this->currentTrackElem = trackElem->getChild(0);
[3335]514}
515
[3836]516
[3335]517/**
[4836]518 *  Sets the trackID we are working on.
519 * @param trackID the trackID we are working on
[3330]520*/
[3836]521void TrackManager::workOn(unsigned int trackID)
[3330]522{
[3836]523  TrackElement* tmpElem = this->firstTrackElem->findByID(trackID);
524  if (tmpElem)
525    this->currentTrackElem = tmpElem;
526  else
527    PRINTF(2)("TrackElement %d not Found, leaving unchanged\n", trackID);
528  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
[3330]529}
530
531/**
[4836]532 *  Sets the TrackElement to work on
533 * @param trackName the Name of the Track to work on
[3330]534*/
[4501]535void TrackManager::workOnS(const char* trackName)
[3330]536{
[3836]537  TrackElement* tmpElem = this->firstTrackElem->findByName(trackName);
[3355]538  if (tmpElem)
539    this->currentTrackElem = tmpElem;
540  else
[3836]541    PRINTF(2)("TrackElement %s not Found, leaving unchanged\n", trackName);
[3594]542  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
[3330]543}
544
545/**
[4836]546 *  Sets the Type of the Curve
547 * @param curveType The Type to set
548 * @param trackElem the TrackElement that should get a new Curve.
[3836]549
[4836]550 *  this will possibly get obsolete during the process.
[3330]551*/
[3433]552void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
[3330]553{
[3433]554  if (!trackElem->isFresh)
[3332]555    {
556      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
557      return;
558    }
[3588]559  this->curveType = curveType;
[3332]560  switch (curveType)
561    {
[3836]562    case CURVE_BEZIER:
[3433]563      trackElem->curve = new BezierCurve();
[3332]564      break;
565    }
[3330]566}
567
568/**
[4836]569 * @param duration the duration of the TrackElement
[4496]570   \see void TrackManager::setDuration(float duration, TrackElement* trackElem)
571*/
572void TrackManager::setDuration(float duration)
573{
574  this->setDuration(duration, NULL);
575}
576
577/**
[4836]578 *  Sets the duration of the current path in seconds.
579 * @param duration The duration in seconds.
580 * @param trackElem The TrackElement to apply this to.
[3330]581*/
[3836]582void TrackManager::setDuration(float duration, TrackElement* trackElem)
[3330]583{
[3836]584  if (!trackElem)
585    trackElem = this->currentTrackElem;
[3330]586
[3836]587  trackElem->duration = duration;
588  trackElem->endTime = trackElem->startingTime + duration;
[3352]589}
590
591/**
[4836]592 *  adds a point to trackElem
593 * @param x x coord
594 * @param y y coord
595 * @param z z coord
596 * @param trackElem The TrackElement to add the Point to
[4496]597*/
598void TrackManager::addPoint(float x, float y, float z)
599{
600  this->addPointV(Vector(x,y,z));
601}
602
603/**
[4836]604 *  adds a point to trackElem
605 * @param newPoint The point to add.
606 * @param trackElem The TrackElement to add the Point to
[3352]607*/
[4496]608void TrackManager::addPointV(Vector newPoint, TrackElement* trackElem)
[3352]609{
[3836]610  if (!trackElem)
611    trackElem = this->currentTrackElem;
612
[3352]613  if (trackElem->isFresh)
[3332]614    {
[3588]615      this->setCurveType(TMAN_DEFAULT_CURVETYPE, trackElem);
[3352]616      trackElem->isFresh = false;
[3332]617    }
[3352]618  trackElem->curve->addNode(newPoint);
619  trackElem->nodeCount++;
[3330]620}
621
622/**
[4836]623 *  adds a new Hot Point
624 * @param x: the x coordinate of the hotpoint
625 * @param y: the y coordinate of the hotpoint
626 * @param z: the z coordinate of the hotpoint
[4509]627   \see int TrackManager::addHotPointV(Vector newPoint, TrackElement* trackElem)
628*/
629void TrackManager::addHotPoint(float x, float y, float z)
630{
631  this->addHotPointV(Vector(x, y, z));
632}
633
634/**
[4836]635 *  adds save/splitpoint.
636 * @param newPoint The point to add.
637 * @param trackElem if supplied it will add a hotpoint on this TrackElement
638 * @returns A Pointer to a newly appended Curve
[3330]639*/
[4509]640int TrackManager::addHotPointV(Vector newPoint, TrackElement* trackElem)
[3330]641{
[3836]642  if (!trackElem)
643    trackElem = this->currentTrackElem;
644
[3594]645  PRINTF(4)("setting up a HotPoint\n");
[3836]646  if (trackElem->isFresh)
[3332]647    {
[3836]648      trackElem->isFresh = false;
[3332]649    }
[3330]650
[4836]651  // @todo HotPoint Handling.
[3836]652  trackElem->curve->addNode(newPoint);
653  trackElem->nodeCount++;
[3837]654  this->initChildren(1, trackElem);
[3330]655}
656
657/**
[4836]658   @todo this must be better
[4496]659*/
[4501]660void TrackManager::setSavePointS(const char* nextElementName)
[4496]661{
[4502]662  this->setSavePoint(NULL);
663  if (strcmp(nextElementName, ""))
664    this->firstTrackElem->findByID(this->trackElemCount)->setName(nextElementName);
[4496]665}
666
667/**
[4836]668 *  Sets the last HotPoint into a savePoint.
669 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
670 * @returns A Pointer to a newly appended Curve
[3837]671
[3330]672   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
673   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
674*/
[4502]675void TrackManager::setSavePoint(TrackElement* trackElem)
[3330]676{
[3837]677  if (!trackElem)
678    trackElem = this->currentTrackElem;
679
[3594]680  PRINTF(4)("setting up a SavePoint.\n");
[3837]681  if (trackElem->isFork || trackElem->isSavePoint)
[3594]682    {
[3837]683      PRINTF(2)("%d is already finished \n", trackElem->ID);
[4502]684      return;
[3594]685    }
[3837]686  trackElem->isSavePoint = true;
687  trackElem->isHotPoint = true;
[3332]688
[3837]689  this->initChildren(1, trackElem);
[3330]690}
691
692/**
[4836]693 *  adds some interessting non-linear movments through the level.
694 * @param count The Count of children the fork will produce
[3330]695
696   If no HotPoint was defined the last added Point will be rendered into a fork. \n
697   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
698*/
[3332]699void TrackManager::fork(unsigned int count, ...)
[3330]700{
[3351]701  int* trackIDs = new int[count];
[4220]702  this->forkV(count, trackIDs, NULL);
[3332]703  va_list ID;
704  va_start (ID, count);
705  for(int i = 0; i < count; i++)
706    {
[3351]707      *va_arg (ID, int*) = trackIDs[i];
[3332]708    }
[4584]709  va_end(ID);
[3332]710  delete []trackIDs;
[3330]711}
712
713/**
[4836]714 * @param count how many children to produce
715 * @param ... the information on the children (these are the Stings of their names
[4220]716   \see TrackManager::fork(unsigned int count, ...)
717
718   does the same as fork, but has an array of strings as an input.
719*/
720void TrackManager::forkS(unsigned int count, ...)
721{
722  int* trackIDs = new int[count];
723  this->forkV(count, trackIDs, NULL);
724  va_list name;
725  va_start (name, count);
726  for(int i = 0; i < count; i++)
727    {
728      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
729    }
[4584]730  va_end(name);
[4220]731  delete []trackIDs;
732}
733
734/**
735   \see TrackManager::fork(unsigned int count, ...)
736*/
737void TrackManager::forkS(const char* forkString)
738{
[5656]739  SubString strings(forkString, ',');
[4220]740
741  int* trackIDs = new int[strings.getCount()];
742  this->forkV(strings.getCount(), trackIDs, NULL);
743
744  for(int i = 0; i < strings.getCount(); i++)
745    {
746      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
[4584]747    }
[4501]748  delete []trackIDs;
[4220]749}
750
751/**
[4836]752 *  adds some interessting non-linear movments through the level.
753 * @param count The Count of childrens the current HotPoint will have.
754 * @param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
755 * @param trackNames the names for the tracks as a char-arrey-array
756 * @param trackElem The TrackElement to appy this to. (if NULL choose this->currentTrackElement)
[3838]757   \see TrackManager::fork(unsigned int count, ...)
[3330]758*/
[4220]759void TrackManager::forkV(unsigned int count, int* trackIDs, char** trackNames, TrackElement* trackElem)
[3330]760{
[3837]761  if (!trackElem)
762    trackElem = this->currentTrackElem;
763
[3594]764  PRINTF(4)("Forking with %d children\n", count);
[3837]765  if (trackElem->isSavePoint)
[3332]766    return;
[3837]767  trackElem->isFork = true;
768  trackElem->isHotPoint = true;
[3351]769  for(int i = 0; i < count; i++)
770    trackIDs[i]=this->trackElemCount+1+i;
[3837]771  this->initChildren(count, trackElem);
[3330]772}
773
774/**
[4836]775 *  decides under what condition a certain Path will be chosen.
776 * @param trackID the trackID to apply this to.
777 * @param cond the CONDITION of the decision
778 * @param subject the Subject that will be decided upon with CONDITION cond.
[3522]779*/
[3837]780void TrackManager::condition(unsigned int trackID, CONDITION cond, void* subject)
[3522]781{
[3837]782  this->condition(cond, subject, this->firstTrackElem->findByID(trackID));
[3522]783}
[3837]784
[3522]785/**
[4836]786 *  decides under what condition a certain Path will be chosen.
787 * @param cond the CONDITION of the decision
788 * @param subject the Subject that will be decided upon with CONDITION cond.
789 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
[3330]790*/
[3837]791void TrackManager::condition(CONDITION cond, void* subject, TrackElement* trackElem)
[3330]792{
[3837]793  if (!trackElem)
794    trackElem = this->currentTrackElem;
795
796  if (!trackElem->isFork)
[3522]797    {
[3837]798      PRINTF(2)("%d is not a Fork, and no condition can be set in this case\n", trackElem->ID);
[3594]799      return;
[3522]800    }
[3594]801  else
802    {
803      switch (cond)
[4584]804        {
805        case LOWEST:
806          trackElem->condFunc = &TrackElement::lowest;
807          break;
808        case HIGHEST:
809          trackElem->condFunc = &TrackElement::highest;
810          break;
811        case RANDOM:
812          trackElem->condFunc = &TrackElement::random;
813          break;
814        case LEFTRIGHT:
815          trackElem->condFunc = &TrackElement::leftRight;
816          break;
817        case NEAREST:
818          trackElem->condFunc = &TrackElement::nearest;
819          break;
820        case ENEMYKILLED:
821          break;
822        }
[3837]823      trackElem->subject=subject;
[3594]824    }
[3330]825}
826
827/**
[4836]828 *  joins some tracks together again.
829 * @param count The count of Paths to join.
[3330]830
831   Join will set the localTime to the longest time a Path has to get to this Point. \n
[3354]832   Join will join all curves to the first curve, meaning that all the tangents will be matched.
[3330]833*/
[3332]834void TrackManager::join(unsigned int count, ...)
[3330]835{
[3332]836  int* trackIDs = new int [count];
837  va_list ID;
838  va_start (ID, count);
839  for(int i = 0; i < count; i++)
840    {
841      trackIDs[i] = va_arg (ID, int);
842    }
843  va_end(ID);
844  this->joinV(count, trackIDs);
845  delete []trackIDs;
[3330]846}
847
848/**
[4836]849 *  Joins some Tracks together again.
850 * @param count The count of trackElements to join
[4220]851   \see void TrackManager::join(unsigned int count, ...)
[3841]852
853   The difference to void TrackManager::join(unsigned int count, ...) is, that this function takes
854   the Names of the TrackElements as inputs and not their ID
855*/
[4220]856void TrackManager::joinS(unsigned int count, ...)
[3841]857{
858  int* trackIDs = new int [count];
859  va_list NAME;
860  va_start (NAME, count);
861  for(int i = 0; i < count; i++)
862    {
[4220]863      const char* name = va_arg (NAME, char*);
[3841]864      TrackElement* tmpElem = this->firstTrackElem->findByName(name);
865      if (tmpElem)
[4584]866        trackIDs[i] = tmpElem->ID;
[3841]867      else
[4584]868        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", name);
[3841]869    }
870  va_end(NAME);
871  this->joinV(count, trackIDs);
872  delete []trackIDs;
873}
874
[4220]875/**
876   \see void TrackManager::join(unsigned int count, ...)
877*/
878void TrackManager::joinS(const char* joinString)
879{
[5656]880  SubString strings(joinString, ',');
[3841]881
[4220]882  int* trackIDs = new int[strings.getCount()];
883  this->joinV(strings.getCount(), trackIDs);
884
[5313]885  for(unsigned int i = 0; i < strings.getCount(); i++)
[4220]886    {
887      TrackElement* tmpElem = this->firstTrackElem->findByName(strings.getString(i));
[5313]888      if (tmpElem != NULL)
[4584]889        trackIDs[i] = tmpElem->ID;
[4220]890      else
[5313]891      {
[4584]892        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", strings.getString(i));
[5313]893        trackIDs[i] = -1;
894      }
[4220]895    }
896  this->joinV(strings.getCount(), trackIDs);
897  delete []trackIDs;
898}
899
[3841]900/**
[4836]901 *  joins some tracks together again.
902 * @param count The count of Paths to join.
903 * @param trackIDs an Array with the trackID's to join
[5335]904 *
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;
[5313]911  for (unsigned int i = 0; i < count; i++)
[3840]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:
[5313]940  for (unsigned int i = 0; i < count; i++)
[3433]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();
[5115]981      TrackElement* enumElem = iterator->firstElement();
[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/**
[4836]995 *  finalizes the TrackSystem. after this it will not be editable anymore
[3433]996
[4836]997   @todo check for any inconsistencies, output errors
[3433]998*/
[4746]999void TrackManager::finalize()
[3433]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();
[5115]1007          TrackElement* enumElem = iterator->firstElement();
[4584]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/**
[4836]1043 *  calculates the Position for the localTime of the Track.
1044 * @returns the calculated Position
[3330]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/**
[4836]1052 *  calculates the Rotation for the localTime of the Track.
1053 * @returns the calculated Rotation
[3330]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/**
[4836]1061 * @returns the current Width of the track
[3596]1062*/
[4746]1063float TrackManager::getWidth() const
[3596]1064{
1065  return this->currentTrackElem->width;
1066}
1067
1068/**
[4836]1069 *  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{
[3591]1076  PRINTF(4)("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
[3348]1077  if (this->localTime <= this->firstTrackElem->duration)
1078    this->jumpTo(this->localTime);
[3601]1079  if (this->localTime <= this->maxTime)
1080    this->localTime += dt;
[3433]1081  if (this->localTime > this->currentTrackElem->endTime
1082      && this->currentTrackElem->children)
1083    {
[3527]1084      if (this->currentTrackElem->jumpTime != 0.0)
[4584]1085        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
[3527]1086      // jump to the next TrackElement and also set the history of the new Element to the old one.
1087      TrackElement* tmpHistoryElem = this->currentTrackElem;
[3594]1088      this->currentTrackElem = this->currentTrackElem->getChild(this->choosePath(this->currentTrackElem));
[3527]1089      this->currentTrackElem->history = tmpHistoryElem;
[3845]1090      if (this->currentTrackElem->getName())
[4584]1091        {
1092          this->trackText->setText(this->currentTrackElem->getName());
1093          this->textAnimation->replay();
1094        }
[3433]1095    }
1096  if (this->bindSlave)
1097    {
1098      Vector tmp = this->calcPos();
[4584]1099      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]1100
1101      Vector v(0.0, 1.0, 0.0);
[3543]1102      Quaternion q(-PI/2, v);
[3539]1103      quat = quat * q;
1104
[3809]1105      this->bindSlave->setAbsCoor(tmp);
1106      this->bindSlave->setAbsDir(quat);
[3433]1107    }
[3330]1108}
1109
1110/**
[4836]1111 *  Jumps to a certain point on the Track.
1112 * @param time The time on the Track to jump to.
[3331]1113
1114   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.)
1115   Max is trackLengthMax.
1116*/
1117void TrackManager::jumpTo(float time)
1118{
[3348]1119  if (time == 0)
[3845]1120    {
1121      this->currentTrackElem = this->firstTrackElem;
1122      if (this->currentTrackElem->getName())
[4584]1123        {
1124          this->trackText->setText(this->currentTrackElem->getName());
1125          this->textAnimation->play();
1126        }
[3845]1127    }
[3348]1128  this->localTime = time;
[3331]1129}
1130
1131/**
[4836]1132 *  a Function that decides which Path we should follow.
1133 * @param trackElem The Path to choose.
[4584]1134
[3330]1135*/
[3522]1136int TrackManager::choosePath(TrackElement* trackElem)
[3330]1137{
[3522]1138  return (trackElem->*(trackElem->condFunc))(trackElem->subject);
[3330]1139}
1140
[3433]1141/**
[4836]1142 *  Sets the PNode, that should be moved along the Tack
1143 * @param bindSlave the PNode to set
[3433]1144*/
1145void TrackManager::setBindSlave(PNode* bindSlave)
1146{
[3556]1147  this->bindSlave = bindSlave;
[3433]1148}
[3350]1149
[3556]1150/**
[4836]1151 * @returns the main TrackNode
[3556]1152*/
[4746]1153PNode* TrackManager::getTrackNode()
[3556]1154{
1155  return this->trackNode;
1156}
[3350]1157
1158// DEBUG //
1159
1160/**
[4836]1161 *  Imports a model of the Graph into the OpenGL-environment.
1162 * @param dt The Iterator used in seconds for Painting the Graph.
[3350]1163
1164   This is for testing facility only. Do this if you want to see the Path inside the Level.
1165   eventually this will all be packed into a gl-list.
1166*/
1167void TrackManager::drawGraph(float dt) const
1168{
1169  for (int i = 1; i <= trackElemCount; i++)
1170    {
[3352]1171      glBegin(GL_LINE_STRIP);
[3836]1172      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
[3350]1173      if (tmpElem->curve)
[4584]1174        for(float f = 0.0; f < 1.0; f+=dt)
1175          {
1176            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
1177            Vector tmpVector = tmpElem->curve->calcPos(f);
1178            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
1179          }
[3710]1180      glEnd();
[3350]1181    }
1182}
1183
[3433]1184/**
[4836]1185 *  outputs debug information about the trackManager
1186 * @param level how much debug
[3433]1187*/
[3350]1188void TrackManager::debug(unsigned int level) const
1189{
[3522]1190  PRINT(0)("=========================================\n");
1191  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
1192  PRINT(0)("=========================================\n");
1193  //  PRINT(0)("Status is: %
1194  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
1195  PRINT(0)(" localTime is: %f\n", this->localTime);
[3350]1196  if (level >= 2)
1197    {
1198      for (int i = 1; i <= trackElemCount; i++)
[4584]1199        {
1200          TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1201          tmpElem->debug();
1202        }
[3350]1203    }
[3522]1204  PRINT(0)("-----------------------------------------\n");
[3350]1205}
Note: See TracBrowser for help on using the repository browser.