Index: /orxonox/branches/levelloader/src/defs/stdincl.h
===================================================================
--- /orxonox/branches/levelloader/src/defs/stdincl.h	(revision 3522)
+++ /orxonox/branches/levelloader/src/defs/stdincl.h	(revision 3523)
@@ -31,4 +31,6 @@
 #include "vector.h"
 
+#include "tinyxml.h"
+
 #include "list.h"
 #include "list_template.h"
Index: /orxonox/branches/levelloader/src/story_entities/world.cc
===================================================================
--- /orxonox/branches/levelloader/src/story_entities/world.cc	(revision 3522)
+++ /orxonox/branches/levelloader/src/story_entities/world.cc	(revision 3523)
@@ -133,71 +133,88 @@
 ErrorMessage World::load()
 {
-	if( 0)	// temporary until we really load from files
-	{
-			GameLoader* loader = GameLoader::getInstance();
-			
-		  if( getPath() == NULL)
-		  {
-				PRINTF(ERR)("World has no path specified for loading");
-				return (ErrorMessage){213,"Path not specified","World::load()"};
-		  }
-		  
-			TiXMLDocument* XMLDoc = new TiXMLDocument( name);
-			// load the campaign document
-			if( !XMLDoc.LoadFile())
-			{
-				// report an error
-				PRINTF(ERR)("Error loading XML File: %s @ %d:%d\n", XMLDoc.ErrorDesc(), XMLDoc.ErrorRow(), XMLDoc.ErrorCol());
-				delete XMLDoc;
-				return (ErrorMessage){213,"XML File parsing error","World::load()"};
-			}
-			
-			// check basic validity
-			TiXMLElement* element = XMLDoc.RootElement();
-			assert( element != NULL);
-			
-			element = element->FirstChildElement( "WorldDataFile");
-			
-			if( element == NULL )
-			{
-				// report an error
-				PRINTF(ERR)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
-				delete XMLDoc;
-				return (ErrorMessage){213,"Path not a WorldDataFile","World::load()"};
-			}
-			
-			// load the parameters
-				// name
-			char* temp;
-			char* string = grabParameter( root, "name");
-			if( string == NULL)
-			{
-				PRINTF(ERR)("World is missing a proper 'name'\n");
-				setStoryId( -1);
-			}
-			else
-			{
-				temp = new char[strlen(string + 2)];
-				worldName = temp;
-			}
-			
-			
-			// find WorldEntities
-		  element = root->FirstChildElement( "WorldEntities");
-		  
-		  // load Players/Objects/Whatever
-			while( element != NULL)
-			{
-				WorldEntity* created = (WorldEntity*) loader->fabricate( element);
-				if( created != NULL) spawn( created);
-				element = element->nextSiblingElement();
-			}
-			
-			// find Track
-				// TODO: load the track somehow
-			
-			// free the XML data
-			delete XMLDoc;
-	}
+	GameLoader* loader = GameLoader::getInstance();
+	
+  if( getPath() == NULL)
+  {
+		PRINTF(ERR)("World has no path specified for loading");
+		return (ErrorMessage){213,"Path not specified","World::load()"};
+  }
+  
+	TiXMLDocument* XMLDoc = new TiXMLDocument( name);
+	// load the campaign document
+	if( !XMLDoc.LoadFile())
+	{
+		// report an error
+		PRINTF(ERR)("Error loading XML File: %s @ %d:%d\n", XMLDoc.ErrorDesc(), XMLDoc.ErrorRow(), XMLDoc.ErrorCol());
+		delete XMLDoc;
+		return (ErrorMessage){213,"XML File parsing error","World::load()"};
+	}
+	
+	// check basic validity
+	TiXMLElement* root = XMLDoc.RootElement();
+	assert( root != NULL);
+	
+	element = root->FirstChildElement( "WorldDataFile");
+	
+	if( root == NULL )
+	{
+		// report an error
+		PRINTF(ERR)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
+		delete XMLDoc;
+		return (ErrorMessage){213,"Path not a WorldDataFile","World::load()"};
+	}
+	
+	// load the parameters
+		// name
+	TiXMLElement* element;
+	char* temp;
+	char* string = grabParameter( root, "name");
+	if( string == NULL)
+	{
+		PRINTF(ERR)("World is missing a proper 'name'\n");
+		setStoryId( -1);
+	}
+	else
+	{
+		temp = new char[strlen(string + 2)];
+		worldName = temp;
+	}
+	
+	
+	// find WorldEntities
+  element = root->FirstChildElement( "WorldEntities");
+  
+  if( element == NULL)
+  {
+		PRINTF(ERR)("World is missing 'WorldEntities'\n");
+  }
+  else
+  {
+  	element = element->FirstChildElement();
+	  // load Players/Objects/Whatever
+		while( element != NULL)
+		{
+			WorldEntity* created = (WorldEntity*) loader->fabricate( element);
+			if( created != NULL) spawn( created);
+			element = element->nextSiblingElement();
+		}
+	}
+	
+	// find Track
+  element = root->FirstChildElement( "Track");
+  if( element == NULL)
+  {
+		PRINTF(ERR)("World is missing a 'Track'\n");
+  }
+  else
+  {	
+  	//load track
+  	trackManager = TrackManager::getInstance();
+  	trackManager->loadTrack( element);
+	}
+  
+	
+	// free the XML data
+	delete XMLDoc;
 	
   //  BezierCurve* tmpCurve = new BezierCurve();
Index: /orxonox/branches/levelloader/src/substring.cc
===================================================================
--- /orxonox/branches/levelloader/src/substring.cc	(revision 3523)
+++ /orxonox/branches/levelloader/src/substring.cc	(revision 3523)
@@ -0,0 +1,88 @@
+/* 
+   orxonox - the future of 3D-vertical-scrollers
+
+   Copyright (C) 2004 orx
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   ### File Specific:
+   main-programmer: Christian Meyer
+   co-programmer: ...
+*/
+
+
+/**
+   \brief breaks a string into parts that were initially seperated by comma
+   \param string the string to break into substrings
+*/
+
+#include "substring.h"
+
+SubString::SubString( char* string)
+{
+	n = 0;
+	
+	assert( string != NULL);
+	
+	for( int i = 0; i < strlen(string); i++) if( string[i] == ',') n++;
+
+	n += 1;
+	
+	strings = malloc( sizeof( char*) * n);
+	
+	int i = 0;
+	int l = 0;
+	
+	char* offset = string;
+	char* end = strchr( string, ',');
+	while( end != NULL)
+	{
+		l = end - offset;
+		strings[i] = malloc( l + 1);
+		strncpy( strings[i], offset, l);
+		i++;
+		end++;
+		offset = end;
+		end = strchr( string, ',');
+	}
+	
+	strings[i] = malloc( l + 1);
+	strncpy( strings[i], offset, l);
+	l = strlen( offset);
+}
+
+/**
+   \brief removes the object from memory
+*/
+SubString::~SubString()
+{
+	for( int i = 0; i < n; i++)
+	{
+		free( strings[i]);
+	}
+	
+	free( strings);
+}
+
+/**
+   \brief get the amount of substrings
+   \returns the amount of substrings
+*/
+int SubString::getN()
+{
+	return n;
+}
+
+/**
+   \brief get a particular substring
+   \param i the ID of the substring to return
+   \returns the designated substring or NULL if an invalid ID was given
+*/
+const char* SubString::getString( int i)
+{
+	if( i < n && i >= 0) return strings[i];
+	else return NULL;
+}
Index: /orxonox/branches/levelloader/src/substring.h
===================================================================
--- /orxonox/branches/levelloader/src/substring.h	(revision 3523)
+++ /orxonox/branches/levelloader/src/substring.h	(revision 3523)
@@ -0,0 +1,21 @@
+/*! 
+    \file substring.h
+    \brief a small class to get the parts of a string separated by commas
+*/
+
+#include "stdincl.h"
+
+class SubString
+{
+	public:
+	
+		SubString( char* string);
+		~SubString();
+		
+		int getN();
+		const char* getString( int i);
+		
+	private:
+		char** strings;
+		int n;
+};
Index: /orxonox/branches/levelloader/src/track_manager.cc
===================================================================
--- /orxonox/branches/levelloader/src/track_manager.cc	(revision 3522)
+++ /orxonox/branches/levelloader/src/track_manager.cc	(revision 3523)
@@ -11,5 +11,5 @@
    ### File Specific:
    main-programmer: Benjamin Grauer
-   co-programmer: ...
+   co-programmer: Christian Meyer
 */
 
@@ -18,4 +18,5 @@
 
 #include "p_node.h"
+#include "substring.h"
 
 #include <stdarg.h>
@@ -105,4 +106,5 @@
 
   PRINTF(3)("Initializing the TrackManager\n");
+  this->namer = new TrackNamer();
   this->firstTrackElem = new TrackElement();
   this->firstTrackElem->ID = 1;
@@ -125,4 +127,5 @@
   PRINTF(3)("Deleting all the TrackElements\n");
   delete this->firstTrackElem;
+  delete this->namer;
 
   // we do not have a TrackManager anymore
@@ -628,2 +631,259 @@
     }
 }
+
+/**
+   \brief loads track data from a XML Element
+   \param root the element containing all track data
+*/
+void TrackManager::loadTrack( TiXMLElement* root)
+{
+	assert( root != NULL);
+	
+	TiXMLElement* element;
+	TiXMLNode* container;
+	double x, y, z, d;
+	
+	element = root->FirstChildElement();
+	
+	while( element != NULL)
+	{
+		if( !strcmp( element->Value(), "Point")
+		{
+			container = element->FirstChild();
+			if( container != NULL && container->Type() == TEXT)
+			{
+				assert( container->Value() != NULL);
+				if( sscanf( container->Value(), "%f,%f,%f", &x, &y, &z) == 3)
+					addPoint( Vector( x, y, z));
+				else
+				{
+					PRINTF(ERR)("Invalid Point in Track (skipped)\n");
+				}			
+			}
+		}
+		else if( !strcmp( element->Value(), "Duration")
+		{
+			container = element->FirstChild();
+			if( container != NULL && container->Type() == TEXT)
+			{
+				assert( container->Value() != NULL);
+				if( sscanf( container->Value(), "%f", &d) == 1)
+					setDuration( d);
+				else
+				{
+					PRINTF(ERR)("Invalid Duration in Track (skipped)\n");
+				}			
+			}
+		}
+		else if( !strcmp( element->Value(), "SavePoint")
+		{
+			setSavePoint();
+		}
+		else if( !strcmp( element->Value(), "Fork")
+		{
+			container = element->FirstChild();
+			if( container != NULL && container->Type() == TEXT)
+			{
+				assert( container->Value() != NULL);
+				forkS( container->Value());
+			}
+		}
+		else if( !strcmp( element->Value(), "Join")
+		{
+			container = element->FirstChild();
+			if( container != NULL && container->Type() == TEXT)
+			{
+				assert( container->Value() != NULL);
+				joinS( container->Value());
+			}
+		}
+		else if( !strcmp( element->Value(), "WorkOn")
+		{
+			container = element->FirstChild();
+			if( container != NULL && container->Type() == TEXT)
+			{
+				assert( container->Value() != NULL);
+				workOnS( container->Value());
+			}
+		}
+		
+		element = element->NextSiblingElement();
+	}
+}
+
+/**
+   \brief forks the current track and names the resulting tracks
+   \param string the names of the new tracks, separated by commas
+   
+   The names used have to be unique within a particular track system.
+*/
+void TrackManager::forkS( char* string)
+{
+	SubString* parts = new SubString( string);
+	int *IDs;
+	int n = parts->getN();
+	
+	assert( n != 0);
+	
+	IDs = new int[n];
+	
+	forkV( n, IDs);
+	
+	for( int i = 0; i < n; i++)
+	{
+		PRINTF(DEBUG)("Track fork '%s'(%d) generated\n", parts->getString( i), IDs[i]);
+		namer->add( parts->getString( i), IDs[i]);
+	}
+		
+	delete IDs;
+	delete parts;
+}
+
+/**
+   \brief joins the named strings
+   \param string the names of the track to be joined, separated by commas
+*/
+void TrackManager::joinS( char* string)
+{
+	SubString* parts = new SubString( string);
+	int *IDs;
+	int n = parts->getN();
+	
+	
+	assert( n != 0);
+	
+	IDs = new int[n];
+	
+	int d, t;
+	d = 0;
+	t = n;
+	
+	PRINTF(DEBUG)("Joining tracks:");
+	
+	for( int i = 0; i < n; i++)
+	{
+		IDs[d] = namer->getIDof( parts->getString( i));
+		if( IDs[d] == -1)
+		{
+			PRINTF(ERR)("Track name '%s' unknown, could not join\n", parts->getString( i));
+			t--;
+		}
+		else
+		{
+			PRINTF(DEBUG)(" '%s'", parts->getString( i));
+			d++;
+		}
+	}
+	
+	PRINTF(DEBUG)("\n");
+
+	joinV( t, IDs);
+		
+	delete IDs;
+	delete parts;
+}
+
+/**
+   \brief set the piece of track to work on
+   \param string the name of the track to work on (must have been previosly set by forkS)
+*/
+void TrackManager::workOnS( char* string)
+{
+	int i;
+	i = namer->getIdof( string);
+	if( i != -1)
+	{
+		WorkOn( i);
+	}
+	else PRINTF(ERR)("'%s' is not a valid TrackIdentifier\n", string);
+}
+
+
+//	------------------------------------------
+// 		TrackNamer
+//	-------------------------------------------
+
+TrackNamer::~TrackNamer()
+{
+	TrackIdentifier* t;
+	
+	while( first != NULL)
+	{
+		t = first;
+		first = first->next;
+		free( t->name);
+		free( t);
+	}
+}
+		
+int TrackNamer::getIDof( const char* name)
+{
+	TrackIdentifier *t;
+	t = first;
+	
+	assert( name != NULL);
+	
+	while( t != NULL)
+	{
+		if( !strcmp( name, t->name)) return t->ID;
+	}
+	
+	return -1;
+}
+
+const char* TrackNamer::getNameof( int ID)
+{
+	TrackIdentifier *t;
+	t = first;
+	
+	assert( ID != -1);
+	
+	while( t != NULL)
+	{
+		if( ID == t->ID) return t->name;
+	}
+	
+	return NULL;
+}
+
+void TrackNamer::add( const char* name, int ID)
+{
+	TrackIdentifier *t, *d;
+	
+	assert( name != NULL);
+	assert( ID != -1);
+	
+	t = malloc( sizeof( TrackIdentifier));
+	t->next = NULL;
+	t->ID = ID;
+	t->name = malloc( strlen( name) + 1);
+	strcpy( t->name, name);
+	
+	if( first == NULL)
+	{
+		first = t;
+	}
+	else
+	{
+		d = first;
+		while( d->next != NULL)
+		{
+			if( ID == d->ID)
+			{
+				PRINTF(ERR)("Track ID %d already named %s (tried to name it %s)\n", ID, d->name, name);
+				free( t->name);
+				free( t);
+				return;
+			}
+			if( !strcmp( name, d->name))
+			{
+				PRINTF(ERR)("Track name %s already used by track ID %d (tried to assign it to track ID %d)<n", name, d->ID, ID); 
+				free( t->name);
+				free( t);
+				return;
+			}
+			d = d->next;
+		}
+		d->next = t;
+	}	
+}
Index: /orxonox/branches/levelloader/src/track_manager.h
===================================================================
--- /orxonox/branches/levelloader/src/track_manager.h	(revision 3522)
+++ /orxonox/branches/levelloader/src/track_manager.h	(revision 3523)
@@ -16,4 +16,5 @@
 
 class PNode;
+class TrackNamer;
 
 //! condition for choosing a certain Path. \todo implement a useful way.
@@ -106,4 +107,5 @@
   int trackElemCount;                 //!< The count of TrackElements that exist.
   PNode* bindSlave;
+	TrackNamer* namer;
   
   void initChildren(unsigned int childCount);
@@ -130,4 +132,10 @@
   void joinV(unsigned int count, int* trackIDs);
   void finalize(void);
+	void forkS( char* string);
+	void joinS( char* string);
+	void workOnS( char* string);
+
+	// Method to load track data from file
+	void loadTrack( TiXMLElement* root);
 
   // Methods to calculate the position on the Path (runtime)
@@ -145,3 +153,24 @@
 };
 
+typedef struct
+{
+	int ID;
+	char* name;
+	struct TrackIdentifier *next;
+} TrackIdentifier;
+
+class TrackNamer
+{
+	public:
+		TrackNamer() { first = NULL};
+		~TrackNamer();
+		
+		int getIDof( const char* name);
+		const char* getNameof( int ID);
+		void add( const char* name, int ID);
+	
+	private:
+		TrackIdentifier* first;	
+};
+
 #endif /* _TRACK_MANAGER_H */
