Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/trackManager/src/track_manager.cc @ 3514

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

orxonox/branches/trackManager: constructed a simple pathChooser-module, with Method-function pointer… really fancy stuff

File size: 20.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16
17#include "track_manager.h"
18
19#include "p_node.h"
20
21#include <stdarg.h>
22#include "p_node.h"
23
24using namespace std;
25
26/**
27   \brief initializes a TrackElement (sets the default values)
28*/
29TrackElement::TrackElement(void)
30{
31  this->isFresh = true;
32  this->isHotPoint = false;
33  this->isSavePoint = false;
34  this->isFork = false;
35  this->isJoined = false;
36  this->mainJoin = false;
37  this->cond; //!< todo think!!
38  this->ID = -1;
39  this->startingTime = 0; //!< \todo eventually set this to the max time of TrackManager.
40  this->duration = 1;
41  this->endTime = 1;
42  this->jumpTime = 0;
43  this->curveType = BEZIERCURVE;
44  this->nodeCount = 0;
45  this->childCount = 0;
46  this->name = NULL;
47  this->curve = NULL;
48  this->children = NULL;
49  this->condFunc = &TrackElement::random;
50}
51
52/**
53    \brief destroys all alocated memory)
54    \todo eventually when deleting a TrackElement you would not like to delete all its preceding TrackElements
55*/
56TrackElement::~TrackElement(void)
57{
58  if (this->name)
59    delete []name;
60  if (this->curve)
61    delete this->curve;
62  if ((!this->isJoined &&this->childCount > 0) || (this->isJoined && this->mainJoin))
63    {
64      for (int i=0; i < this->childCount; i++)
65        delete this->children[i];
66      delete this->children;
67    }
68}
69
70/**
71   \brief Searches through all the TrackElements for trackID.
72   \param trackID The ID to search for.
73   \returns The TrackElement if Found, NULL otherwise.
74   
75   \todo make this more modular, to search for different things
76*/
77TrackElement* TrackElement::findByID(unsigned int trackID)
78{
79  // return if Found.
80  if (this->ID == trackID)
81    return this;
82  // search on.
83  if (this->childCount > 0)
84    for (int i=0; i < this->childCount; i++)
85      {
86        TrackElement* tmpElem;
87        if ((tmpElem = this->children[i]->findByID(trackID)))
88          return tmpElem;
89      }
90  else return NULL;
91}
92
93
94/**
95   \brief checks if there are any BackLoops in the Track
96   \param trackElem the trackElement to check about
97   it simply does this by looking if the current trackElem is found again somewhere else in the Track
98*/
99bool TrackElement::backLoopCheck(TrackElement* trackElem)
100{
101  if (this->childCount == 0)
102    return true;
103  else
104    {
105      for (int i = 0; i < this->childCount; i++)
106        if(!this->children[i]->backLoopCheck(trackElem))
107          return false;
108     
109      return true;
110    }
111}
112
113int TrackElement::lowest(void* nothing)
114{
115  return 0;
116}
117
118int TrackElement::highest(void* nothing)
119{ 
120  return this->childCount-1;
121}
122
123int TrackElement::random(void* nothing)
124{
125  if (this->childCount == 0)
126    return 0;
127  else
128    {
129      int i = (int)floor ((float)rand()/(float)RAND_MAX * (float)this->childCount);
130      if (i >= this->childCount)
131        return this->childCount-1;
132      else 
133        return i;
134    }
135}
136
137
138/////////////////////////////////////
139///// TRACKMANAGER //////////////////
140/////////////////////////////////////
141/**
142   \brief standard constructor
143
144*/
145TrackManager::TrackManager(void)
146{
147  this->setClassName ("TrackManager");
148
149  PRINTF(3)("Initializing the TrackManager\n");
150  this->firstTrackElem = new TrackElement();
151  this->firstTrackElem->ID = 1;
152  this->currentTrackElem = firstTrackElem;
153  this->localTime = 0;
154  this->maxTime = 0;
155  this->trackElemCount = 1;
156  this->bindSlave = NULL;
157}
158
159
160/**
161   \brief standard destructor
162
163*/
164TrackManager::~TrackManager(void)
165{
166  PRINTF(3)("Destruct TrackManager\n");
167
168  PRINTF(3)("Deleting all the TrackElements\n");
169  delete this->firstTrackElem;
170
171  // we do not have a TrackManager anymore
172  singletonRef = NULL;
173}
174
175TrackManager* TrackManager::singletonRef = NULL;
176
177/**
178   \returns The reference on the TrackManager.
179
180   If the TrackManager does not exist, it will be created.
181*/
182TrackManager* TrackManager::getInstance(void) 
183{
184  if (TrackManager::singletonRef)
185    return TrackManager::singletonRef;
186  else
187    return TrackManager::singletonRef = new TrackManager();
188}
189
190/**
191   \brief reserves Space for childCount children
192   \param childCount The Count of children to make space for.
193*/
194void TrackManager::initChildren(unsigned int childCount)
195{
196  this->currentTrackElem->childCount = childCount;
197  this->currentTrackElem->mainJoin = true;
198  this->currentTrackElem->children = new TrackElement*[childCount];
199  for (int i=0; i<childCount; i++)
200    {
201      this->currentTrackElem->children[i] = new TrackElement();
202      this->currentTrackElem->children[i]->ID = ++trackElemCount;
203      this->currentTrackElem->children[i]->startingTime = this->currentTrackElem->endTime + this->currentTrackElem->jumpTime;
204      this->addPoint(this->currentTrackElem->curve->getNode(this->currentTrackElem->curve->getNodeCount()), this->currentTrackElem->children[i]);
205    }
206}
207
208/**
209   \brief Searches for a given trackID.
210   \param trackID the trackID to search for.
211   \returns The TrackElement #trackID if found, NULL otherwise.
212*/
213TrackElement* TrackManager::findTrackElementByID(unsigned int trackID) const
214{
215  return firstTrackElem->findByID(trackID);
216}
217
218// INITIALIZE //
219
220/**
221   \brief Sets the trackID we are working on.
222   \param trackID the trackID we are working on
223*/
224void TrackManager::workOn(unsigned int trackID)
225{
226  TrackElement* tmpElem = findTrackElementByID(trackID);
227  if (tmpElem)
228    this->currentTrackElem = tmpElem;
229  else
230    printf("TrackElement not Found, leaving unchanged\n");
231  printf("now Working on %d\n", this->currentTrackElem->ID);
232
233}
234
235/**
236   \brief Sets the Type of the Curve
237   \brief curveType The Type to set
238*/
239void TrackManager::setCurveType(CurveType curveType, TrackElement* trackElem)
240{
241  if (!trackElem->isFresh)
242    {
243      PRINTF(2)("It is not possible to change the type of a Curve after you have have appended some points to it\n");
244      return;
245    }
246  trackElem->curveType = curveType;
247  switch (curveType)
248    {
249    case BEZIERCURVE:
250      trackElem->curve = new BezierCurve();
251      break;
252    case UPOINTCURVE:
253      trackElem->curve = new UPointCurve();
254      break;
255    }
256}
257
258/**
259   \brief Sets the duration of the current path in seconds.
260   \param time The duration in seconds.
261*/
262
263void TrackManager::setDuration(float time)
264{
265  this->currentTrackElem->duration = time;
266  this->currentTrackElem->endTime = this->currentTrackElem->startingTime + time;
267}
268
269/**
270   \brief adds a point to the current TrackElement
271   \param newPoint The point to add.
272*/
273bool TrackManager::addPoint(Vector newPoint)
274{
275  return this->addPoint(newPoint, this->currentTrackElem);
276}
277
278/**
279   \brief adds a point to trackElem
280   \param newPoint The point to add.
281   \param trackElem The TrackElement to add the Point to
282*/
283bool TrackManager::addPoint(Vector newPoint, TrackElement* trackElem)
284{
285  if (trackElem->isFresh)
286    {
287      this->setCurveType(BEZIERCURVE, trackElem);
288      trackElem->isFresh = false;
289    }
290  trackElem->curve->addNode(newPoint);
291  trackElem->nodeCount++;
292}
293
294/**
295   \brief adds save/splitpoint.
296   \param newPoint The point to add.
297   \returns A Pointer to a newly appended Curve
298*/
299int TrackManager::addHotPoint(Vector newPoint)
300{
301  printf("setting up a HotPoint\n");
302  if (this->currentTrackElem->isFresh)
303    {
304      this->setCurveType(BEZIERCURVE);
305      this->currentTrackElem->isFresh = false;
306    }
307
308  // \todo HotPoint Handling.
309  this->currentTrackElem->curve->addNode(newPoint);
310  this->currentTrackElem->nodeCount++;
311  this->initChildren(1);
312  this->currentTrackElem = this->currentTrackElem->children[0];
313}
314
315/**
316   \brief Sets the last HotPoint into a savePoint.
317   \returns A Pointer to a newly appended Curve
318   
319   If no HotPoint was defined the last added Point will be rendered into a savePoint. \n
320   If the HotPoint was defined as a fork the Point will \b not be set into a savePoint.
321*/
322int TrackManager::setSavePoint(void)
323{
324  printf("setting up a SavePoint.\n");
325  if (this->currentTrackElem->isFork || this->currentTrackElem->isSavePoint)
326    return this->currentTrackElem->children[1]->ID;
327  this->currentTrackElem->isSavePoint = true;
328  this->currentTrackElem->isHotPoint = true;
329
330  this->initChildren(1);
331  this->currentTrackElem = this->currentTrackElem->children[0];
332}
333
334/**
335   \brief adds some interessting non-linear movments through the level.
336   \param count The Count of childrens the current HotPoint will have.
337
338   If no HotPoint was defined the last added Point will be rendered into a fork. \n
339   If the HotPoint was defined as a savePoint the Point will \b not be set into a fork.
340*/
341void TrackManager::fork(unsigned int count, ...)
342{
343  int* trackIDs = new int[count];
344  this->forkV(count, trackIDs);
345  va_list ID;
346  va_start (ID, count);
347  for(int i = 0; i < count; i++)
348    {
349      *va_arg (ID, int*) = trackIDs[i];
350    }
351  va_end(ID); 
352  delete []trackIDs;
353}
354
355/**
356   \brief adds some interessting non-linear movments through the level.
357   \param count The Count of childrens the current HotPoint will have.
358   \param trackIDs A Pointer to an Array of ints which will hold the trackID's (the user will have to reserve space for this).
359
360   \see void TrackManager::fork(int count, ...)
361
362   \todo initialisation is wrong!! also in setSavePoint.
363*/
364void TrackManager::forkV(unsigned int count, int* trackIDs)
365{
366  printf("Forking with %d children\n", count);
367  if (this->currentTrackElem->isSavePoint)
368    return;
369  this->currentTrackElem->isFork = true;
370  this->currentTrackElem->isHotPoint = true;
371  for(int i = 0; i < count; i++)
372    trackIDs[i]=this->trackElemCount+1+i;
373  this->initChildren(count);
374}
375
376/**
377   \brief decides under what condition a certain Path will be chosen.
378   \param groupID the ID on which to choose the preceding move
379   \param cond \todo think about this
380*/
381void TrackManager::condition(unsigned int groupID, PathCondition cond)
382{
383 
384}
385
386/**
387   \brief joins some tracks together again.
388   \param count The count of Paths to join.
389
390   Join will set the localTime to the longest time a Path has to get to this Point. \n
391   Join will join all curves to the first curve, meaning that all the tangents will be matched.
392*/
393void TrackManager::join(unsigned int count, ...)
394{
395  int* trackIDs = new int [count];
396  va_list ID;
397  va_start (ID, count);
398  for(int i = 0; i < count; i++)
399    {
400      trackIDs[i] = va_arg (ID, int);
401    }
402  va_end(ID);
403  this->joinV(count, trackIDs);
404  delete []trackIDs;
405}
406
407/**
408   \brief joins some tracks together again.
409   \param count The count of Paths to join.
410   \param trackIDs an Array with the trackID's to join
411
412   \see void TrackManager::join(int count, ...)
413*/
414void TrackManager::joinV(unsigned int count, int* trackIDs)
415{
416  printf("Joining %d tracks and merging to Track %d\n", count, trackIDs[0]);
417
418  // checking if there is a back-loop-connection and ERROR if it is.
419  TrackElement* tmpTrackElem = this->findTrackElementByID(trackIDs[0]);
420  if (!tmpTrackElem->backLoopCheck(tmpTrackElem))
421    PRINTF(1)("Backloop connection detected at joining trackElements\n");
422
423  // chanching work-on to temporary value. going back at the end.
424  int tmpCurrentWorkingID = this->currentTrackElem->ID;
425  this->workOn(trackIDs[0]);
426  TrackElement* firstJoint = this->currentTrackElem;
427  float tmpLatestTime = firstJoint->endTime;
428
429  Vector tmpEndPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount());
430  Vector tmpTangentPoint = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-1);
431  Vector tmpc2Point = firstJoint->curve->getNode(firstJoint->curve->getNodeCount()-2);
432  firstJoint->isJoined = true;
433  //  firstJoint->mainJoin = true;
434  if(!firstJoint->isHotPoint)
435    this->setSavePoint();
436  // Timing:
437  for (int i = 0; i < count; i++)
438    {
439      TrackElement* tmpJoinElem = this->findTrackElementByID(trackIDs[i]);
440      if (tmpJoinElem->childCount == 0
441          && tmpJoinElem->endTime > tmpLatestTime)
442        tmpLatestTime = tmpJoinElem->endTime;
443    }
444  // time the main Join.
445  firstJoint->jumpTime = tmpLatestTime - firstJoint->endTime;
446 
447  // Joining:
448  for (int i = 1; i < count; i++)
449    {
450      TrackElement* tmpJoinElem = this->findTrackElementByID(trackIDs[i]);
451      if (tmpJoinElem->childCount > 0)
452        printf("!!This Curve has children, and as such will not be joined!!\n You can try joining other childless TrackElements to this one!");
453      else
454        {
455          this->addPoint(tmpc2Point, tmpJoinElem);
456          this->addPoint(tmpTangentPoint, tmpJoinElem);
457          this->addPoint(tmpEndPoint, tmpJoinElem);
458          // time all other Joins
459          tmpJoinElem->jumpTime = tmpLatestTime - tmpJoinElem->endTime;
460         
461          //Copying Joint-Info
462          tmpJoinElem->children = firstJoint->children;
463          tmpJoinElem->childCount = firstJoint->childCount;
464          tmpJoinElem->isSavePoint = firstJoint->isSavePoint;
465          tmpJoinElem->isFork = firstJoint->isFork;
466
467          tmpJoinElem->isJoined = true;
468        }
469    }
470  if(firstJoint->childCount > 0)
471    for(int i = 0; i < firstJoint->childCount; i++)
472      {
473        printf("Setting startingTime of %d to %f.\n", firstJoint->children[i]->ID, tmpLatestTime);
474        firstJoint->children[i]->startingTime = tmpLatestTime;
475        firstJoint->children[i]->endTime = tmpLatestTime+firstJoint->children[i]->duration;
476      } 
477
478  // returning to the TrackElement we were working on.
479  this->workOn(tmpCurrentWorkingID);
480}
481
482/**
483   \brief finalizes the TrackSystem. after this it will not be editable anymore
484
485   \todo check for any inconsistencies, output errors
486*/
487void TrackManager::finalize(void)
488{
489  for (int i = 1; i<= trackElemCount ;i++)
490    {
491      TrackElement* tmpElem = findTrackElementByID(i);
492      if (tmpElem->childCount>0 && tmpElem->mainJoin)
493        {
494          for (int j = 0; j < tmpElem->childCount; j++)
495            {
496             
497              // c1-continuity
498              tmpElem->children[j]->curve->addNode(tmpElem->children[j]->curve->getNode(0) +
499                                                   ((tmpElem->children[j]->curve->getNode(0) - 
500                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1))
501                                                    ),2);
502              tmpElem->children[j]->nodeCount++;
503              // c2-continuity
504              tmpElem->children[j]->curve->addNode((tmpElem->curve->getNode(tmpElem->curve->getNodeCount())-
505                                                    tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-1)) * 4 +
506                                                   tmpElem->curve->getNode(tmpElem->curve->getNodeCount()-2), 3);
507              tmpElem->children[j]->nodeCount++;                                                   
508              printf("accelerations: %d-in: count: %d, %f, %f, %f\n                  %d-out: count: %d %f, %f, %f\n",
509                     tmpElem->ID, tmpElem->nodeCount,
510                     tmpElem->curve->calcAcc(0.999).x, tmpElem->curve->calcAcc(0.999).y, tmpElem->curve->calcAcc(0.999).z,
511                     tmpElem->children[j]->ID, tmpElem->children[j]->nodeCount,
512                     tmpElem->children[j]->curve->calcAcc(0).x, tmpElem->children[j]->curve->calcAcc(0).y, tmpElem->children[j]->curve->calcAcc(0).z);
513            }
514        }
515    }
516}
517
518
519// RUNTIME //
520
521/**
522   \brief calculates the Position for the localTime of the Track.
523   \returns the calculated Position
524*/
525Vector TrackManager::calcPos() const
526{
527  //  PRINTF(0)("TrackElement:%d, localTime: %f\n",this->currentTrackElem->ID, this->localTime);
528  return this->currentTrackElem->curve->calcPos((this->localTime-this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
529}
530
531/**
532   \brief calculates the Rotation for the localTime of the Track.
533   \returns the calculated Rotation
534*/
535Vector TrackManager::calcDir() const
536{
537  return this->currentTrackElem->curve->calcDir((this->localTime - this->currentTrackElem->startingTime)/this->currentTrackElem->duration);
538}
539
540/**
541   \brief Advances the local-time of the Track around dt
542   \param dt The time about which to advance.
543
544   This function also checks, if the TrackElement has to be changed.
545*/
546void TrackManager::tick(float dt)
547{
548  dt /= 1000;
549  printf("CurrentTrackID: %d, LocalTime is: %f, timestep is: %f\n", this->currentTrackElem->ID, this->localTime, dt);
550  if (this->localTime <= this->firstTrackElem->duration)
551    this->jumpTo(this->localTime);
552  this->localTime += dt;
553  if (this->localTime > this->currentTrackElem->endTime
554      && this->currentTrackElem->children)
555    {
556      if (this->currentTrackElem->jumpTime > 0)
557        this->jumpTo(this->localTime + this->currentTrackElem->jumpTime);
558      this->currentTrackElem = this->currentTrackElem->children[this->choosePath(this->currentTrackElem)];
559    }
560  if (this->bindSlave)
561    {
562      Vector tmp = this->calcPos();
563      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)); 
564      this->bindSlave->setAbsCoor(&tmp);
565      this->bindSlave->setAbsDir(&quat);
566    }
567}
568
569/**
570   \brief Jumps to a certain point on the Track.
571   \param time The time on the Track to jump to.
572
573   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.)
574   Max is trackLengthMax.
575*/
576void TrackManager::jumpTo(float time)
577{
578  if (time == 0)
579    this->currentTrackElem = this->firstTrackElem;
580  this->localTime = time;
581}
582
583/**
584   \brief a Function that decides which Path we should follow.
585   \param trackElem The Path to choose.
586   
587*/
588int TrackManager::choosePath(TrackElement* trackElem)
589{
590  return (trackElem->*(trackElem->condFunc))(NULL);
591}
592
593/**
594   \brief Sets the PNode, that should be moved along the Tack
595   \param bindSlave the PNode to set
596*/
597void TrackManager::setBindSlave(PNode* bindSlave)
598{
599  if (!this->bindSlave)
600    this->bindSlave = bindSlave;
601}
602
603
604// DEBUG //
605
606/**
607   \brief Imports a model of the Graph into the OpenGL-environment.
608   \param dt The Iterator used in seconds for Painting the Graph.
609
610   This is for testing facility only. Do this if you want to see the Path inside the Level.
611   eventually this will all be packed into a gl-list.
612*/
613void TrackManager::drawGraph(float dt) const
614{
615
616  for (int i = 1; i <= trackElemCount; i++)
617    {
618      glBegin(GL_LINE_STRIP);
619      TrackElement* tmpElem = this->findTrackElementByID(i);
620      if (tmpElem->curve)
621        for(float f = 0.0; f < 1.0; f+=dt)
622          {
623            //      printf("%f, %f, %f\n",trackManager->calcPos().x, trackManager->calcPos().y, trackManager->calcPos().z);
624            Vector tmpVector = tmpElem->curve->calcPos(f);
625            glVertex3f(tmpVector.x, tmpVector.y, tmpVector.z);
626          }
627  glEnd();
628    }
629}
630
631/**
632   \brief outputs debug information about the trackManager
633   \param level how much debug
634*/
635void TrackManager::debug(unsigned int level) const
636{
637  PRINT(0)("=========================================\n");
638  PRINT(0)("= CLASS TRACKMANAGER::debug information =\n");
639  PRINT(0)("=========================================\n");
640  //  PRINT(0)("Status is: %
641  PRINT(0)(" Consists of %d elements\n", this->trackElemCount);
642  PRINT(0)(" localTime is: %f\n", this->localTime);
643  if (level >= 2)
644    {
645      for (int i = 1; i <= trackElemCount; i++)
646        {
647          TrackElement* tmpElem = this->findTrackElementByID(i);
648          PRINT(0)("--== TrackElement:%i ==--", tmpElem->ID);
649          if(tmpElem->name)
650            PRINT(0)("Name: %s::", tmpElem->name);
651          if(tmpElem->isFresh)
652            PRINT(0)("  -- has not jet eddited in any way --\n");
653          PRINT(0)("\n   TimeTable: startingTime=%f; endTime=%f; duration=%f; jumpTime=%f\n", tmpElem->startingTime, tmpElem->endTime, tmpElem->duration, tmpElem->jumpTime);
654          PRINT(0)("   consists of %d Points\n", tmpElem->nodeCount);
655          if (tmpElem->childCount == 0)
656            PRINT(0)("   has no child\n");
657          else if (tmpElem->childCount == 1)
658            PRINT(0)("   has 1 child: =%d=\n", tmpElem->children[0]->ID);
659          else if (tmpElem->childCount > 1)
660            {
661              PRINT(0)("   has %d children: ", tmpElem->childCount);
662              for(int i = 0; i < tmpElem->childCount; i++)
663                PRINT(0)("=%d= ", tmpElem->children[i]->ID);
664              PRINT(0)("\n");
665            }
666
667          if(tmpElem->isHotPoint)
668            PRINT(0)("   is a special Point:\n");
669          if(tmpElem->isSavePoint)
670            PRINT(0)("    is a SavePoint\n");
671          if(tmpElem->isFork)
672            {
673              PRINT(0)("    is A Fork with with %d children.\n", tmpElem->childCount);
674            }
675          if(tmpElem->isJoined)
676            PRINT(0)("   is Joined at the End\n");
677
678          if(!tmpElem->backLoopCheck(tmpElem)) /* this should not happen */
679            PRINT(2)(" THERE IS A BACKLOOP TO THIS ELEMENT\n");
680        }
681    }
682  PRINT(0)("-----------------------------------------\n");
683}
Note: See TracBrowser for help on using the repository browser.