/***************************************************************************
 *            track.h
 *
 *  Sat Nov 19 10:45:47 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  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 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#ifndef _TRACK_H

#include "bezier.h"
#include "objects.h"
#include "configfile.h"

#include <sstream>

using namespace std;

#include "globals.h"

#define BEZIER_COLLIDE_FUNCTION CollideSubDivQuadSimpleNorm

#define LEAVES_PER_BBOX 1

class BEZIERNODE
{
public:
	BEZIER patch;
	BEZIERNODE * next;
	BEZIERNODE() {next = NULL;}
};

class BEZIERCOLBRANCH
{
public:
	BEZIERCOLBRANCH();
	void DeleteChildren();
	AABB bbox;
	BEZIERCOLBRANCH * left; 
	BEZIERCOLBRANCH * right;
	list <BEZIER *> leaves;
};

class ROADSTRIP
{
private:
	void ClearPatches();
	void GenerateCollisionTree();
	BEZIERCOLBRANCH coltree;
	void GenerateBranches(BEZIERCOLBRANCH * branch);
	BEZIER * lastcolpatch;
	
public:
	//BEZIERNODE * patchnodes;
	list <BEZIER> patchnodes;
	ROADSTRIP();
	~ROADSTRIP() {coltree.DeleteChildren();ClearPatches();}
	BEZIER * Add(BEZIER & newpatch);
	BEZIER * AddNew();
	bool ReadFrom(ifstream &openfile);
	bool WriteTo(ofstream &openfile);
	bool DeleteLastPatch();
	void Visualize (bool wireframe, bool fill, VERTEX color);
	BEZIER * GetLastPatch();
	BEZIER * GetFirstPatch() {return &(patchnodes.front());}
	int NumPatches();
	bool Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest);
	bool Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch, VERTEX & normal);
	bool CollideBruteForce(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch);
	bool CollideBranch(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch, BEZIERCOLBRANCH * branch, VERTEX & normal);
	void Reverse();
};

class ROADSTRIPNODE
{
public:
	ROADSTRIP road;
	ROADSTRIPNODE * next;
	ROADSTRIPNODE() {next = NULL;}
};

class TRACK
{
private:
	ROADSTRIPNODE * roads;
	int NumRoads();
	std::vector<VERTEX> startloc;
	double lastelev;
	std::vector<QUATERNION> startquat;
	bool cullfaces;
	bool verticaltrackingskyboxes;
	vector <BEZIER *> lapsequence;

	float friction1; //the friction coefficient for non-treaded tires
	float friction2; //the friction coefficient for treaded tires
	
	BEZIER * GetBezier(int ridx, int pidx);

	void ReverseStartingPositions();

	bool direction; //true = forward, false = reverse
	
public:
	TRACK();
	~TRACK();
	ROADSTRIP * AddNewRoad();
	void VisualizeRoads(bool wireframe, bool fill, ROADSTRIP * selectedroad);
	void ClearRoads();
	void Reverse();
	void Write(string trackname);
	void Load(string trackname) {Load(trackname, false);}
	void Load(string trackname, bool reverse);
	void Delete(ROADSTRIP * striptodel);
	double Elevation(VERTEX origin);
	double Elevation(VERTEX origin, VERTEX & normal);
	double ElevationSeg(VERTEX origin, VERTEX & normal, float seglen);
	double ElevationSeg(VERTEX origin, VERTEX & normal, float seglen, BEZIER * &collidepatch, OBJECTNODE * &colnode);
	bool Collide(VERTEX origin, VERTEX direction, float seglen, VERTEX &outtri, bool closest, VERTEX & normal, float & dist);
	bool CollideD(VERTEXD origin, VERTEXD direction, double seglen, VERTEXD &outtri, bool closest, VERTEXD & normal, double & dist);
	bool CollideRoads(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, ROADSTRIP * &collideroad, BEZIER * &collidepatch, VERTEX & normal);
	bool CollideModel(VERTEX * modelverts, int numfaces, AABB bbox, VERTEX & outtri, bool closest, VERTEX & normal, float & depth);
	void SetStart(VERTEX newloc) {startloc.push_back(newloc);}
	VERTEX GetStart(unsigned int i) {return (i>=startloc.size())?startloc[0]:startloc[i];}
	BEZIER * GetPatch(VERTEX corners[4]);
	QUATERNION GetStartOrientation(unsigned int i) {return (i>=startquat.size())?startquat[0]:startquat[i];}
	void SetStartOrientation(QUATERNION newquat) {startquat.push_back(newquat);}
	bool GetCullFaces() {return cullfaces;}
	bool GetVerticalTrackingSkyboxes() {return verticaltrackingskyboxes;}
	BEZIER * GetLapSequence(int idx);
	int NumSectors() {return lapsequence.size();}
	void GetFrictionParams(float & f1out, float & f2out) {f1out = friction1;f2out = friction2;}
	bool GetDirection() { return direction;};
	ROADSTRIPNODE* GetRoads() {return roads;}
};

#define _TRACK_H
#endif /* _TRACK_H */
