/*  TA3D, a remake of Total Annihilation
    Copyright (C) 2005  Roland BROCHARD

    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*/

/*-----------------------------------------------------------------\
|                               tdf.h                              |
|   contient toutes les fonctions et classes permettant la gestion |
| des fichiers TDF du jeu Total Annihilation qui contienne divers  |
| éléments graphiques.                                             |
\-----------------------------------------------------------------*/

#ifndef __CLASSES_TDF

#define __CLASSES_TDF

#include "gaf.h"			// Pour la gestion des fichiers GAF
#include "particles.h"		// Pour l'accès au moteur à particules
#include "3do.h"			// Pour pouvoir utiliser des modèles 3D

class FEATURE
{
public:
	char	*name;		// Nom
	char	*world;
	char	*description;
	char	*category;
	bool	animating;
	int		footprintx;
	int		footprintz;
	int		height;
	char	*filename;
	char	*seqname;
	bool	animtrans;
	bool	shadtrans;
	int		hitdensity;
	int		metal;
	int		damage;
	bool	indestructible;
	ANIM	anim;
	bool	vent;
	bool	m3d;
	MODEL	*model;
	bool	converted;		// Indique si l'objet a été converti en 3d depuis un sprite

	void init()
	{
		converted=false;
		m3d=false;
		model=NULL;
		vent=false;
		name=NULL;
		world=NULL;
		description=NULL;
		category=NULL;
		animating=false;
		footprintx=0;
		footprintz=0;
		height=0;
		filename=NULL;
		seqname=NULL;
		animtrans=false;
		shadtrans=false;
		hitdensity=0;
		metal=0;
		damage=0;
		indestructible=false;
		anim.init();
	}

	FEATURE()
	{
		init();
	}

	void destroy()
	{
		if(name)		free(name);
		if(world)		free(world);
		if(description)	free(description);
		if(category)	free(category);
		if(filename)	free(filename);
		if(seqname)		free(seqname);
		anim.destroy();
		init();
	}

	~FEATURE()
	{
		destroy();
	}
};

class FEATURE_MANAGER
{
public:
	int		nb_features;
	FEATURE	*feature;

	void init()
	{
		nb_features=0;
		feature=NULL;
	}

	FEATURE_MANAGER()
	{
		init();
	}

	void destroy()
	{
		if(nb_features>0 && feature)			// Détruit les éléments
			for(int i=0;i<nb_features;i++)
				feature[i].destroy();
		if(feature)
			free(feature);
		init();
	}

	~FEATURE_MANAGER()
	{
		destroy();
	}

	void clean()
	{
		if(feature==NULL) return;
		for(int i=0;i<nb_features;i++)
			feature[i].anim.clean();
	}

	int add_feature(char *name)			// Ajoute un élément
	{
		nb_features++;
		FEATURE *n_feature=(FEATURE*) malloc(sizeof(FEATURE)*nb_features);
		if(feature && nb_features>1)
			for(int i=0;i<nb_features-1;i++)
				n_feature[i]=feature[i];
		if(feature)	free(feature);
		feature=n_feature;
		feature[nb_features-1].init();
		feature[nb_features-1].name=strdup(name);
		return nb_features-1;
	}

private:
	inline char *get_line(char *data)
	{
		int pos=0;
		while(data[pos]!=0 && data[pos]!=13 && data[pos]!=10)	pos++;
		char *d=new char[pos+1];
		memcpy(d,data,pos);
		d[pos]=0;
		return d;
	}
public:

	void load_tdf(char *data,int size=99999999);					// Charge un fichier tdf

	int get_feature_index(char *name)
	{
		if(nb_features<=0)	return -1;
		for(int i=0;i<nb_features;i++)
			if(strcasecmp(name,feature[i].name)==0)
				return i;
		for(int i=0;i<nb_features;i++)
			if(feature[i].filename!=NULL && strcasecmp(name,feature[i].filename)==0)
				return i;
		for(int i=0;i<nb_features;i++)
			if(feature[i].seqname!=NULL && strcasecmp(name,feature[i].seqname)==0)
				return i;
		return -1;
	}
};

extern FEATURE_MANAGER		feature_manager;

void load_all_features_in_hpi(char *filename);

void load_features();				// Charge tout les éléments

struct FEATURE_DATA
{
	VECTOR	Pos;		// Position spatiale de l'élément
	int		type;		// Type d'élément
	short	frame;		// Pour l'animation
	float	dt;			// Pour la gestion du temps
	bool	draw;		// Indique si l'objet est dessiné
};

class FEATURES					// Moteur de gestion des éléments graphiques
{
public:
	int				nb_features;		// Nombre d'éléments à gérer
	int				max_features;		// Quantité maximale d'éléments que l'on peut charger dans la mémoire allouée
	FEATURE_DATA	*feature;			// Eléments
	int				min_idx;			// Indices des premiers et derniers éléments du tableau à être affichés
	int				max_idx;

	void init()
	{
		nb_features=0;
		max_features=0;
		feature=NULL;
		min_idx=0;
		max_idx=0;
	}

	FEATURES()
	{
		init();
	}

	void destroy()
	{
		if(feature)
			free(feature);
		init();
	}

	~FEATURES()
	{
		destroy();
	}

	int add_feature(VECTOR Pos,int type)
	{
		if(type<0 || type>=feature_manager.nb_features)	return -1;
		nb_features++;
		if(nb_features>max_features) {			// Si besoin alloue plus de mémoire
			max_features+=100;				// Alloue la mémoire par paquets de 100 éléments
			FEATURE_DATA	*n_feature=(FEATURE_DATA*) malloc(sizeof(FEATURE_DATA)*max_features);
			if(feature && nb_features>0)
				for(int i=0;i<nb_features-1;i++)
					n_feature[i]=feature[i];
			if(feature)	free(feature);
			feature=n_feature;
			}
		feature[nb_features-1].Pos=Pos;
		feature[nb_features-1].type=type;
		feature[nb_features-1].frame=0;
		feature[nb_features-1].draw=false;
		return nb_features-1;
	}

	void delete_feature(int index)
	{
		if(nb_features<=0) return;
		nb_features--;
		if(index<nb_features)
			for(int i=index;i<nb_features;i++)
				feature[i]=feature[i+1];
	}

	void move(float dt)
	{
		POINTF O;
		O.x=O.y=O.z=0.0f;
		for(int i=min_idx;i<=max_idx;i++) {
			if(!feature_manager.feature[feature[i].type].vent) {
				feature[i].draw=false;
				continue;
				}
			feature[i].dt+=dt;
			if(feature[i].dt>0.2f && feature[i].draw) {
				feature[i].dt=0.0f;
				particle_engine.make_smoke(O+feature[i].Pos,0,1,5.0f);
				}
			feature[i].draw=false;
			}
	}

	void draw(CAMERA *cam);

	void draw_shadow(CAMERA *cam,VECTOR Dir);
};

extern FEATURES features;

#endif
