Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: minor nicessity fixes. no real bugs traced → :(

File size: 35.8 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"
[3845]26#include "text_engine.h"
[3849]27#include "t_animation.h"
[4496]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/**
[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/**
[4836]93 *  Searches through all the TrackElements for trackID.
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
[5122]382  this->trackText = TextEngine::getInstance()->createText("fonts/earth.ttf", 30, TEXT_RENDER_DYNAMIC);
[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
[4834]400  LOAD_PARAM_START_CYCLE
401
[4501]402      LoadParam<TrackManager>(element, "WorkOn", this, &TrackManager::workOnS, true)
[4584]403        .describe("Selects a TrackElement (by name) to work on");
[4501]404
[4496]405      LoadParam<TrackManager>(element, "Point", this, &TrackManager::addPoint, true)
[4584]406        .describe("Adds a new Point to the currently selected TrackElement");
[4496]407
408      LoadParam<TrackManager>(element, "Duration", this, &TrackManager::setDuration, true)
[4584]409        .describe("Sets the Duration of the currently selected TrackElement");
[4509]410
411      LoadParam<TrackManager>(element, "HotPoint", this, &TrackManager::addHotPoint, true)
[4584]412        .describe("Sets a new Point that acts as a hot point. meaning, the curve will flow through this Point");
413
[4501]414      LoadParam<TrackManager>(element, "SavePoint", this, &TrackManager::setSavePointS, true)
[4584]415        .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]416
[4501]417      LoadParam<TrackManager>(element, "Fork", this, &TrackManager::forkS, true)
[4584]418        .describe("Forks the Path into multiple forked Path names seperated by ','");
[4501]419
420      LoadParam<TrackManager>(element, "Join", this, &TrackManager::joinS, true)
[4584]421        .describe("Joins multiple joining Path names seperated by ','");
[4501]422
[4496]423      /*
[4584]424        if( !strcmp( element->Value(), "Fork"))
425        {
426        container = element->FirstChild();
427        if( container->ToText())
428        {
429        assert( container->Value() != NULL);
430        PRINTF(4)("Loaded Fork: %s\n", container->Value());
431        forkS(container->Value());
432        }
433        }
[4496]434      */
[4501]435      /*
[4584]436        if( !strcmp( element->Value(), "Join"))
437        {
438        container = element->FirstChild();
439        if( container->ToText())
440        {
441        assert( container->Value() != NULL);
442        PRINTF0("Loaded Join: %s\n", container->Value());
443        joinS(container->Value());
444        }
445        }
446      */
[4834]447      LOAD_PARAM_END_CYCLE;
[4017]448}
449
450/**
[4836]451 *  standard destructor
[3311]452*/
[4746]453TrackManager::~TrackManager()
[3330]454{
[3331]455  PRINTF(3)("Destruct TrackManager\n");
[3311]456
[3594]457  PRINTF(4)("Deleting all the TrackElements\n");
[3331]458  delete this->firstTrackElem;
[3335]459
[5079]460  delete this->trackText;
[3836]461  // the tracknode should be deleted here, but is deleted by pNode: -> null_parent
462
[3331]463  // we do not have a TrackManager anymore
[3594]464  TrackManager::singletonRef = NULL;
[3330]465}
466
[3543]467//! Singleton Reference to TrackManager
[3331]468TrackManager* TrackManager::singletonRef = NULL;
469
[3836]470// INITIALIZE //
[3331]471/**
[4836]472 *  reserves Space for childCount children
473 * @param childCount The Count of children to make space for.
474 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
[3335]475*/
[3836]476void TrackManager::initChildren(unsigned int childCount, TrackElement* trackElem)
[3335]477{
[3836]478  if (!trackElem)
479    trackElem = this->currentTrackElem;
480
481  trackElem->childCount = childCount;
482  trackElem->mainJoin = true;  // this tells join, that this one is the Main Join, if it tries to join multiple Tracks
483  trackElem->children =  new tList<TrackElement>();
[3594]484  for (int i = 0; i < childCount; i++)
[3348]485    {
[3836]486      // create a new Element
[3594]487      TrackElement* newElem = new TrackElement();
[3836]488      // setting up the new ID
[3594]489      newElem->ID = ++trackElemCount;
[3836]490      // setting up the Time
491      newElem->startingTime = trackElem->endTime + trackElem->jumpTime;
492      // adds the conection Point
[4496]493      this->addPointV(trackElem->curve->getNode(trackElem->curve->getNodeCount()),
[4584]494                     newElem);
[3836]495      // add the new child to the childList.
496      trackElem->children->add(newElem);
[3348]497    }
[3836]498
[3842]499  // setting the Name of the new TrackElement to the name of the last one + _childI
[3837]500
[3842]501  if (trackElem->getName())
502    {
503      for (int i = 0; i < trackElem->childCount; i++)
504      {
[4584]505        char* childName = new char[strlen(trackElem->getName())+10];
506        sprintf(childName, "%s_child%d", trackElem->getName(), i);
507        trackElem->getChild(i)->setName(childName);
[3842]508      }
509    }
[3837]510  // select the first Child to work on.
511  this->currentTrackElem = trackElem->getChild(0);
[3335]512}
513
[3836]514
[3335]515/**
[4836]516 *  Sets the trackID we are working on.
517 * @param trackID the trackID we are working on
[3330]518*/
[3836]519void TrackManager::workOn(unsigned int trackID)
[3330]520{
[3836]521  TrackElement* tmpElem = this->firstTrackElem->findByID(trackID);
522  if (tmpElem)
523    this->currentTrackElem = tmpElem;
524  else
525    PRINTF(2)("TrackElement %d not Found, leaving unchanged\n", trackID);
526  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
[3330]527}
528
529/**
[4836]530 *  Sets the TrackElement to work on
531 * @param trackName the Name of the Track to work on
[3330]532*/
[4501]533void TrackManager::workOnS(const char* trackName)
[3330]534{
[3836]535  TrackElement* tmpElem = this->firstTrackElem->findByName(trackName);
[3355]536  if (tmpElem)
537    this->currentTrackElem = tmpElem;
538  else
[3836]539    PRINTF(2)("TrackElement %s not Found, leaving unchanged\n", trackName);
[3594]540  PRINTF(4)("now Working on %d\n", this->currentTrackElem->ID);
[3330]541}
542
543/**
[4836]544 *  Sets the Type of the Curve
545 * @param curveType The Type to set
546 * @param trackElem the TrackElement that should get a new Curve.
[3836]547
[4836]548 *  this will possibly get obsolete during the process.
[3330]549*/
[3433]550void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
[3330]551{
[3433]552  if (!trackElem->isFresh)
[3332]553    {
554      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
555      return;
556    }
[3588]557  this->curveType = curveType;
[3332]558  switch (curveType)
559    {
[3836]560    case CURVE_BEZIER:
[3433]561      trackElem->curve = new BezierCurve();
[3332]562      break;
563    }
[3330]564}
565
566/**
[4836]567 * @param duration the duration of the TrackElement
[4496]568   \see void TrackManager::setDuration(float duration, TrackElement* trackElem)
569*/
570void TrackManager::setDuration(float duration)
571{
572  this->setDuration(duration, NULL);
573}
574
575/**
[4836]576 *  Sets the duration of the current path in seconds.
577 * @param duration The duration in seconds.
578 * @param trackElem The TrackElement to apply this to.
[3330]579*/
[3836]580void TrackManager::setDuration(float duration, TrackElement* trackElem)
[3330]581{
[3836]582  if (!trackElem)
583    trackElem = this->currentTrackElem;
[3330]584
[3836]585  trackElem->duration = duration;
586  trackElem->endTime = trackElem->startingTime + duration;
[3352]587}
588
589/**
[4836]590 *  adds a point to trackElem
591 * @param x x coord
592 * @param y y coord
593 * @param z z coord
594 * @param trackElem The TrackElement to add the Point to
[4496]595*/
596void TrackManager::addPoint(float x, float y, float z)
597{
598  this->addPointV(Vector(x,y,z));
599}
600
601/**
[4836]602 *  adds a point to trackElem
603 * @param newPoint The point to add.
604 * @param trackElem The TrackElement to add the Point to
[3352]605*/
[4496]606void TrackManager::addPointV(Vector newPoint, TrackElement* trackElem)
[3352]607{
[3836]608  if (!trackElem)
609    trackElem = this->currentTrackElem;
610
[3352]611  if (trackElem->isFresh)
[3332]612    {
[3588]613      this->setCurveType(TMAN_DEFAULT_CURVETYPE, trackElem);
[3352]614      trackElem->isFresh = false;
[3332]615    }
[3352]616  trackElem->curve->addNode(newPoint);
617  trackElem->nodeCount++;
[3330]618}
619
620/**
[4836]621 *  adds a new Hot Point
622 * @param x: the x coordinate of the hotpoint
623 * @param y: the y coordinate of the hotpoint
624 * @param z: the z coordinate of the hotpoint
[4509]625   \see int TrackManager::addHotPointV(Vector newPoint, TrackElement* trackElem)
626*/
627void TrackManager::addHotPoint(float x, float y, float z)
628{
629  this->addHotPointV(Vector(x, y, z));
630}
631
632/**
[4836]633 *  adds save/splitpoint.
634 * @param newPoint The point to add.
635 * @param trackElem if supplied it will add a hotpoint on this TrackElement
636 * @returns A Pointer to a newly appended Curve
[3330]637*/
[4509]638int TrackManager::addHotPointV(Vector newPoint, TrackElement* trackElem)
[3330]639{
[3836]640  if (!trackElem)
641    trackElem = this->currentTrackElem;
642
[3594]643  PRINTF(4)("setting up a HotPoint\n");
[3836]644  if (trackElem->isFresh)
[3332]645    {
[3836]646      trackElem->isFresh = false;
[3332]647    }
[3330]648
[4836]649  // @todo HotPoint Handling.
[3836]650  trackElem->curve->addNode(newPoint);
651  trackElem->nodeCount++;
[3837]652  this->initChildren(1, trackElem);
[3330]653}
654
655/**
[4836]656   @todo this must be better
[4496]657*/
[4501]658void TrackManager::setSavePointS(const char* nextElementName)
[4496]659{
[4502]660  this->setSavePoint(NULL);
661  if (strcmp(nextElementName, ""))
662    this->firstTrackElem->findByID(this->trackElemCount)->setName(nextElementName);
[4496]663}
664
665/**
[4836]666 *  Sets the last HotPoint into a savePoint.
667 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
668 * @returns A Pointer to a newly appended Curve
[3837]669
[3330]670   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
671   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
672*/
[4502]673void TrackManager::setSavePoint(TrackElement* trackElem)
[3330]674{
[3837]675  if (!trackElem)
676    trackElem = this->currentTrackElem;
677
[3594]678  PRINTF(4)("setting up a SavePoint.\n");
[3837]679  if (trackElem->isFork || trackElem->isSavePoint)
[3594]680    {
[3837]681      PRINTF(2)("%d is already finished \n", trackElem->ID);
[4502]682      return;
[3594]683    }
[3837]684  trackElem->isSavePoint = true;
685  trackElem->isHotPoint = true;
[3332]686
[3837]687  this->initChildren(1, trackElem);
[3330]688}
689
690/**
[4836]691 *  adds some interessting non-linear movments through the level.
692 * @param count The Count of children the fork will produce
[3330]693
694   If no HotPoint was defined the last added Point will be rendered into a fork. \n
695   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
696*/
[3332]697void TrackManager::fork(unsigned int count, ...)
[3330]698{
[3351]699  int* trackIDs = new int[count];
[4220]700  this->forkV(count, trackIDs, NULL);
[3332]701  va_list ID;
702  va_start (ID, count);
703  for(int i = 0; i < count; i++)
704    {
[3351]705      *va_arg (ID, int*) = trackIDs[i];
[3332]706    }
[4584]707  va_end(ID);
[3332]708  delete []trackIDs;
[3330]709}
710
711/**
[4836]712 * @param count how many children to produce
713 * @param ... the information on the children (these are the Stings of their names
[4220]714   \see TrackManager::fork(unsigned int count, ...)
715
716   does the same as fork, but has an array of strings as an input.
717*/
718void TrackManager::forkS(unsigned int count, ...)
719{
720  int* trackIDs = new int[count];
721  this->forkV(count, trackIDs, NULL);
722  va_list name;
723  va_start (name, count);
724  for(int i = 0; i < count; i++)
725    {
726      this->firstTrackElem->findByID(trackIDs[i])->setName(va_arg(name, const char*));
727    }
[4584]728  va_end(name);
[4220]729  delete []trackIDs;
730}
731
732/**
733   \see TrackManager::fork(unsigned int count, ...)
734*/
735void TrackManager::forkS(const char* forkString)
736{
737  SubString strings(forkString);
738
739  int* trackIDs = new int[strings.getCount()];
740  this->forkV(strings.getCount(), trackIDs, NULL);
741
742  for(int i = 0; i < strings.getCount(); i++)
743    {
744      this->firstTrackElem->findByID(trackIDs[i])->setName(strings.getString(i));
[4584]745    }
[4501]746  delete []trackIDs;
[4220]747}
748
749/**
[4836]750 *  adds some interessting non-linear movments through the level.
751 * @param count The Count of childrens the current HotPoint will have.
752 * @param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
753 * @param trackNames the names for the tracks as a char-arrey-array
754 * @param trackElem The TrackElement to appy this to. (if NULL choose this->currentTrackElement)
[3838]755   \see TrackManager::fork(unsigned int count, ...)
[3330]756*/
[4220]757void TrackManager::forkV(unsigned int count, int* trackIDs, char** trackNames, TrackElement* trackElem)
[3330]758{
[3837]759  if (!trackElem)
760    trackElem = this->currentTrackElem;
761
[3594]762  PRINTF(4)("Forking with %d children\n", count);
[3837]763  if (trackElem->isSavePoint)
[3332]764    return;
[3837]765  trackElem->isFork = true;
766  trackElem->isHotPoint = true;
[3351]767  for(int i = 0; i < count; i++)
768    trackIDs[i]=this->trackElemCount+1+i;
[3837]769  this->initChildren(count, trackElem);
[3330]770}
771
772/**
[4836]773 *  decides under what condition a certain Path will be chosen.
774 * @param trackID the trackID to apply this to.
775 * @param cond the CONDITION of the decision
776 * @param subject the Subject that will be decided upon with CONDITION cond.
[3522]777*/
[3837]778void TrackManager::condition(unsigned int trackID, CONDITION cond, void* subject)
[3522]779{
[3837]780  this->condition(cond, subject, this->firstTrackElem->findByID(trackID));
[3522]781}
[3837]782
[3522]783/**
[4836]784 *  decides under what condition a certain Path will be chosen.
785 * @param cond the CONDITION of the decision
786 * @param subject the Subject that will be decided upon with CONDITION cond.
787 * @param trackElem The TrackElement to appy this to. (if NULL chose this->currentTrackElement)
[3330]788*/
[3837]789void TrackManager::condition(CONDITION cond, void* subject, TrackElement* trackElem)
[3330]790{
[3837]791  if (!trackElem)
792    trackElem = this->currentTrackElem;
793
794  if (!trackElem->isFork)
[3522]795    {
[3837]796      PRINTF(2)("%d is not a Fork, and no condition can be set in this case\n", trackElem->ID);
[3594]797      return;
[3522]798    }
[3594]799  else
800    {
801      switch (cond)
[4584]802        {
803        case LOWEST:
804          trackElem->condFunc = &TrackElement::lowest;
805          break;
806        case HIGHEST:
807          trackElem->condFunc = &TrackElement::highest;
808          break;
809        case RANDOM:
810          trackElem->condFunc = &TrackElement::random;
811          break;
812        case LEFTRIGHT:
813          trackElem->condFunc = &TrackElement::leftRight;
814          break;
815        case NEAREST:
816          trackElem->condFunc = &TrackElement::nearest;
817          break;
818        case ENEMYKILLED:
819          break;
820        }
[3837]821      trackElem->subject=subject;
[3594]822    }
[3330]823}
824
825/**
[4836]826 *  joins some tracks together again.
827 * @param count The count of Paths to join.
[3330]828
829   Join will set the localTime to the longest time a Path has to get to this Point. \n
[3354]830   Join will join all curves to the first curve, meaning that all the tangents will be matched.
[3330]831*/
[3332]832void TrackManager::join(unsigned int count, ...)
[3330]833{
[3332]834  int* trackIDs = new int [count];
835  va_list ID;
836  va_start (ID, count);
837  for(int i = 0; i < count; i++)
838    {
839      trackIDs[i] = va_arg (ID, int);
840    }
841  va_end(ID);
842  this->joinV(count, trackIDs);
843  delete []trackIDs;
[3330]844}
845
846/**
[4836]847 *  Joins some Tracks together again.
848 * @param count The count of trackElements to join
[4220]849   \see void TrackManager::join(unsigned int count, ...)
[3841]850
851   The difference to void TrackManager::join(unsigned int count, ...) is, that this function takes
852   the Names of the TrackElements as inputs and not their ID
853*/
[4220]854void TrackManager::joinS(unsigned int count, ...)
[3841]855{
856  int* trackIDs = new int [count];
857  va_list NAME;
858  va_start (NAME, count);
859  for(int i = 0; i < count; i++)
860    {
[4220]861      const char* name = va_arg (NAME, char*);
[3841]862      TrackElement* tmpElem = this->firstTrackElem->findByName(name);
863      if (tmpElem)
[4584]864        trackIDs[i] = tmpElem->ID;
[3841]865      else
[4584]866        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", name);
[3841]867    }
868  va_end(NAME);
869  this->joinV(count, trackIDs);
870  delete []trackIDs;
871}
872
[4220]873/**
874   \see void TrackManager::join(unsigned int count, ...)
875*/
876void TrackManager::joinS(const char* joinString)
877{
878  SubString strings(joinString);
[3841]879
[4220]880  int* trackIDs = new int[strings.getCount()];
881  this->joinV(strings.getCount(), trackIDs);
882
[5313]883  for(unsigned int i = 0; i < strings.getCount(); i++)
[4220]884    {
885      TrackElement* tmpElem = this->firstTrackElem->findByName(strings.getString(i));
[5313]886      if (tmpElem != NULL)
[4584]887        trackIDs[i] = tmpElem->ID;
[4220]888      else
[5313]889      {
[4584]890        PRINTF(1)("Trying to join a Track, of which the name does not exist: %s\n", strings.getString(i));
[5313]891        trackIDs[i] = -1;
892      }
[4220]893    }
894  this->joinV(strings.getCount(), trackIDs);
895  delete []trackIDs;
896}
897
[3841]898/**
[4836]899 *  joins some tracks together again.
900 * @param count The count of Paths to join.
901 * @param trackIDs an Array with the trackID's to join
[3330]902
[3841]903   \see void TrackManager::join(unsigned int count, ...)
[3330]904*/
[3332]905void TrackManager::joinV(unsigned int count, int* trackIDs)
[3330]906{
[3840]907  TrackElement* tmpTrackElem;
[3880]908  TrackElement* tmpJoinElem;
[5313]909  for (unsigned int i = 0; i < count; i++)
[3840]910    if (!this->firstTrackElem->findByID(trackIDs[i]))
911      {
[4584]912        PRINTF(1)("Trying to Connect Paths that do not exist yet: %d\n Not Joining Anything\n", trackIDs[i]);
913        return;
[3840]914      }
915
[4584]916
[3594]917  PRINTF(3)("Joining %d tracks and merging to Track %d\n", count, trackIDs[0]);
[3354]918
[3522]919  // checking if there is a back-loop-connection and ERROR if it is.
[3840]920  tmpTrackElem = this->firstTrackElem->findByID(trackIDs[0]);
[4508]921  if (!tmpTrackElem->backLoopCheck())
[3838]922    {
923      PRINTF(2)("Backloop connection detected at joining trackElements\n -> TRACK WILL NOT BE JOINED\n");
924      return;
925    }
[3522]926
[3838]927  TrackElement* firstJoint =   this->firstTrackElem->findByID(trackIDs[0]);
[3433]928  float tmpLatestTime = firstJoint->endTime;
[3354]929
930  Vector tmpEndPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount());
[3433]931  Vector tmpTangentPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-1);
932  Vector tmpc2Point = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-2);
[3354]933  firstJoint->isJoined = true;
[3433]934  //  firstJoint->mainJoin = true;
[3354]935  if(!firstJoint->isHotPoint)
[3838]936    this->setSavePoint(firstJoint);
[3433]937  // Timing:
[5313]938  for (unsigned int i = 0; i < count; i++)
[3433]939    {
[3880]940      if(tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
[4584]941        {
942          if (tmpJoinElem->childCount == 0
943              && tmpJoinElem->endTime > tmpLatestTime)
944            tmpLatestTime = tmpJoinElem->endTime;
945        }
[3433]946    }
947  // time the main Join.
948  firstJoint->jumpTime = tmpLatestTime - firstJoint->endTime;
[4584]949
[3433]950  // Joining:
[3354]951  for (int i = 1; i < count; i++)
[3352]952    {
[3880]953      if( tmpJoinElem = this->firstTrackElem->findByID(trackIDs[i]))
[4584]954        {
955          if (tmpJoinElem->childCount > 0)
956            printf("!!This Curve has children, and as such will not be joined!!\n You can try joining other childless TrackElements to this one!");
957          else
958            {
959              this->addPointV(tmpc2Point, tmpJoinElem);
960              this->addPointV(tmpTangentPoint, tmpJoinElem);
961              this->addPointV(tmpEndPoint, tmpJoinElem);
962              // time all other Joins
963              tmpJoinElem->jumpTime = tmpLatestTime - tmpJoinElem->endTime;
964
965              //Copying Joint-Info
966              tmpJoinElem->children = firstJoint->children;
967              tmpJoinElem->childCount = firstJoint->childCount;
968              tmpJoinElem->isSavePoint = firstJoint->isSavePoint;
969              tmpJoinElem->isFork = firstJoint->isFork;
970
971              tmpJoinElem->isJoined = true;
972            }
973        }
[3352]974    }
[3838]975  if(firstJoint->children)
[3594]976    {
[3832]977      //TrackElement* enumElem = firstJoint->children->enumerate();
978      tIterator<TrackElement>* iterator = firstJoint->children->getIterator();
[5115]979      TrackElement* enumElem = iterator->firstElement();
[3594]980      while (enumElem)
[4584]981        {
982          PRINTF(5)("Setting startingTime of %d to %f.\n", enumElem->ID, tmpLatestTime);
983          enumElem->startingTime = tmpLatestTime;
984          enumElem->endTime = tmpLatestTime + enumElem->duration;
985
986          enumElem = iterator->nextElement();
987        }
[3832]988      delete iterator;
[3594]989    }
[3330]990}
991
[3433]992/**
[4836]993 *  finalizes the TrackSystem. after this it will not be editable anymore
[3433]994
[4836]995   @todo check for any inconsistencies, output errors
[3433]996*/
[4746]997void TrackManager::finalize()
[3433]998{
999  for (int i = 1; i<= trackElemCount ;i++)
1000    {
[3836]1001      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
[3832]1002      if( tmpElem->childCount > 0 && tmpElem->mainJoin)
[4584]1003        {
1004          tIterator<TrackElement>* iterator = tmpElem->children->getIterator();
[5115]1005          TrackElement* enumElem = iterator->firstElement();
[4584]1006          //TrackElement* enumElem = tmpElem->children->enumerate();
1007          while (enumElem)
1008            {
1009
1010              // c1-continuity
1011              enumElem->curve->addNode(enumElem->curve->getNode(0) +
1012                                                   ((enumElem->curve->getNode(0) -
1013                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1))
1014                                                    ),2);
1015              enumElem->nodeCount++;
1016              // c2-continuity
1017              enumElem->curve->addNode((tmpElem->curve->getNode(tmpElem->curve->getNodeCount())-
1018                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1)) * 4 +
1019                                                   tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-2), 3);
1020              enumElem->nodeCount++;
1021              PRINTF(5)("accelerations: %d-in: count: %d, %f, %f, %f\n                  %d-out: count: %d %f, %f, %f\n",
1022                     tmpElem->ID, tmpElem->nodeCount,
1023                     tmpElem->curve->calcAcc(0.999).x, tmpElem->curve->calcAcc(0.999).y, tmpElem->curve->calcAcc(0.999).z,
1024                     enumElem->ID, enumElem->nodeCount,
1025                     enumElem->curve->calcAcc(0).x, enumElem->curve->calcAcc(0).y, enumElem->curve->calcAcc(0).z);
1026
1027              enumElem = iterator->nextElement();
1028            }
1029          delete iterator;
1030        }
[3433]1031    }
[3838]1032  for (int i = 1; i <= trackElemCount;i++)
[3836]1033    if (this->firstTrackElem->findByID(i)->endTime > this->maxTime)
1034      this->maxTime = this->firstTrackElem->findByID(i)->endTime; // very bad implemented :/
[3433]1035}
1036
1037
[3330]1038// RUNTIME //
1039
1040/**
[4836]1041 *  calculates the Position for the localTime of the Track.
1042 * @returns the calculated Position
[3330]1043*/
[3332]1044Vector TrackManager::calcPos() const
[3330]1045{
[3348]1046  return this->currentTrackElem->curve->calcPos((this->localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
[3330]1047}
1048
1049/**
[4836]1050 *  calculates the Rotation for the localTime of the Track.
1051 * @returns the calculated Rotation
[3330]1052*/
[3332]1053Vector TrackManager::calcDir() const
[3330]1054{
[3433]1055  return this->currentTrackElem->curve->calcDir((this->localTime - this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
[3330]1056}
1057
1058/**
[4836]1059 * @returns the current Width of the track
[3596]1060*/
[4746]1061float TrackManager::getWidth() const
[3596]1062{
1063  return this->currentTrackElem->width;
1064}
1065
1066/**
[4836]1067 *  Advances the local-time of the Track around dt
1068 * @param dt The time about which to advance.
[3333]1069
1070   This function also checks, if the TrackElement has to be changed.
[3330]1071*/
1072void TrackManager::tick(float dt)
1073{
[3591]1074  PRINTF(4)("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
[3348]1075  if (this->localTime <= this->firstTrackElem->duration)
1076    this->jumpTo(this->localTime);
[3601]1077  if (this->localTime <= this->maxTime)
1078    this->localTime += dt;
[3433]1079  if (this->localTime > this->currentTrackElem->endTime
1080      && this->currentTrackElem->children)
1081    {
[3527]1082      if (this->currentTrackElem->jumpTime != 0.0)
[4584]1083        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
[3527]1084      // jump to the next TrackElement and also set the history of the new Element to the old one.
1085      TrackElement* tmpHistoryElem = this->currentTrackElem;
[3594]1086      this->currentTrackElem = this->currentTrackElem->getChild(this->choosePath(this->currentTrackElem));
[3527]1087      this->currentTrackElem->history = tmpHistoryElem;
[3845]1088      if (this->currentTrackElem->getName())
[4584]1089        {
1090          this->trackText->setText(this->currentTrackElem->getName());
1091          this->textAnimation->replay();
1092        }
[3433]1093    }
1094  if (this->bindSlave)
1095    {
1096      Vector tmp = this->calcPos();
[4584]1097      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]1098
1099      Vector v(0.0, 1.0, 0.0);
[3543]1100      Quaternion q(-PI/2, v);
[3539]1101      quat = quat * q;
1102
[3809]1103      this->bindSlave->setAbsCoor(tmp);
1104      this->bindSlave->setAbsDir(quat);
[3433]1105    }
[3330]1106}
1107
1108/**
[4836]1109 *  Jumps to a certain point on the Track.
1110 * @param time The time on the Track to jump to.
[3331]1111
1112   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.)
1113   Max is trackLengthMax.
1114*/
1115void TrackManager::jumpTo(float time)
1116{
[3348]1117  if (time == 0)
[3845]1118    {
1119      this->currentTrackElem = this->firstTrackElem;
1120      if (this->currentTrackElem->getName())
[4584]1121        {
1122          this->trackText->setText(this->currentTrackElem->getName());
1123          this->textAnimation->play();
1124        }
[3845]1125    }
[3348]1126  this->localTime = time;
[3331]1127}
1128
1129/**
[4836]1130 *  a Function that decides which Path we should follow.
1131 * @param trackElem The Path to choose.
[4584]1132
[3330]1133*/
[3522]1134int TrackManager::choosePath(TrackElement* trackElem)
[3330]1135{
[3522]1136  return (trackElem->*(trackElem->condFunc))(trackElem->subject);
[3330]1137}
1138
[3433]1139/**
[4836]1140 *  Sets the PNode, that should be moved along the Tack
1141 * @param bindSlave the PNode to set
[3433]1142*/
1143void TrackManager::setBindSlave(PNode* bindSlave)
1144{
[3556]1145  this->bindSlave = bindSlave;
[3433]1146}
[3350]1147
[3556]1148/**
[4836]1149 * @returns the main TrackNode
[3556]1150*/
[4746]1151PNode* TrackManager::getTrackNode()
[3556]1152{
1153  return this->trackNode;
1154}
[3350]1155
1156// DEBUG //
1157
1158/**
[4836]1159 *  Imports a model of the Graph into the OpenGL-environment.
1160 * @param dt The Iterator used in seconds for Painting the Graph.
[3350]1161
1162   This is for testing facility only. Do this if you want to see the Path inside the Level.
1163   eventually this will all be packed into a gl-list.
1164*/
1165void TrackManager::drawGraph(float dt) const
1166{
1167  for (int i = 1; i <= trackElemCount; i++)
1168    {
[3352]1169      glBegin(GL_LINE_STRIP);
[3836]1170      TrackElement* tmpElem = this->firstTrackElem->findByID(i);
[3350]1171      if (tmpElem->curve)
[4584]1172        for(float f = 0.0; f < 1.0; f+=dt)
1173          {
1174            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
1175            Vector tmpVector = tmpElem->curve->calcPos(f);
1176            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
1177          }
[3710]1178      glEnd();
[3350]1179    }
1180}
1181
[3433]1182/**
[4836]1183 *  outputs debug information about the trackManager
1184 * @param level how much debug
[3433]1185*/
[3350]1186void TrackManager::debug(unsigned int level) const
1187{
[3522]1188  PRINT(0)("=========================================\n");
1189  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
1190  PRINT(0)("=========================================\n");
1191  //  PRINT(0)("Status is: %
1192  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
1193  PRINT(0)(" localTime is: %f\n", this->localTime);
[3350]1194  if (level >= 2)
1195    {
1196      for (int i = 1; i <= trackElemCount; i++)
[4584]1197        {
1198          TrackElement* tmpElem = this->firstTrackElem->findByID(i);
1199          tmpElem->debug();
1200        }
[3350]1201    }
[3522]1202  PRINT(0)("-----------------------------------------\n");
[3350]1203}
Note: See TracBrowser for help on using the repository browser.