//
// this file by brian martin 1996
// brian@phyast.pitt.edu
//
// this is part of the source for the MedDLe quake model viewer/editor
//
//
#include "mdl.h"


void read_mdl(FILE *in, MDL_model *model)
{
	int i,j,k;
	int tx, ty;

	fread(&model->filetype,4,1,in);       // magic nums
	fread(&model->version,4,1,in);        // version 6 now
	fread(&model->xscale,4,1,in);         // scale = (max - min)/255.9
	fread(&model->yscale,4,1,in);
	fread(&model->zscale,4,1,in);
	fread(&model->xoffset,4,1,in);        // min
	fread(&model->yoffset,4,1,in);
	fread(&model->zoffset,4,1,in);
	fread(&model->radius,4,1,in);         // bounding radius
	fread(&model->eyex,4,1,in);             // eye position
	fread(&model->eyey,4,1,in);
	fread(&model->eyez,4,1,in);
	fread(&model->num_skins,4,1,in);      // num skins
	fread(&model->skinw,4,1,in);        // skin width
	fread(&model->skinh,4,1,in);        // skin height
	fread(&model->num_vertices,4,1,in);
	fread(&model->num_triangles,4,1,in);
	fread(&model->num_frames,1,4,in);
	fread(&model->sync_type,1,4,in);          // sync type, either 0 or random
	fread(&model->flags,4,1,in);          // flags
	fread(&model->ave_size,4,1,in);       // average size  pixels/triangle?
	/// that ends the header
	printf("v:%d t:%d f:%d \n",model->num_vertices,model->num_triangles,model->num_frames);

	tx=wherex();
	ty=wherey();
	// now the skin stuff
	model->skin = new (MDL_model_skin)[model->num_skins];
	for(k=0; k<model->num_skins; k++)
	{
		gotoxy(tx,ty);
		printf("reading skin: %d \n",k );
		fread(&model->skin[k].type,4,1,in);
		if(model->skin[k].type==0)
		{
			model->skin[k].bitmap = new (unsigned char)[model->skinw*model->skinh];
			for(j=0;j<model->skinh;j++)
			{
				for(i=0;i<model->skinw;i++)
				{
					fread(model->skin[k].bitmap+(i+model->skinw*j),1,1,in);
				}
			}

		}
		else
		{
			printf("group skin %d : ",k );
			fread(&model->skin[k].num_gskins,4,1,in);
			model->skin[k].gskin_interval = new (float)[model->skin[k].num_gskins];
			model->skin[k].gskin = new (MDL_group_skin)[model->skin[k].num_gskins];
			for(j=0; j<model->skin[k].num_gskins; j++)
			{
				fread(&model->skin[k].gskin_interval[j],4,1,in);

			}
			for(j=0; j<model->skin[k].num_gskins; j++)
			{

				printf("sub skin %d\n ",j );
				for(int jj=0;jj<model->skinh;jj++)
				{
					for(int ii=0;ii<model->skinw;ii++)
					{
						fread(model->skin[k].gskin[j].bitmap+(ii+model->skinw*jj),1,1,in);
					}
				}
			}


		}

	}

	// now read the 2d vertices
	model->vertex = new (unsigned)[model->num_vertices*3];

	for(i=0;i<model->num_vertices;i++)
	{
		fread(model->vertex+i*3,4,1,in);
		fread(model->vertex+i*3+1,4,1,in);
		fread(model->vertex+i*3+2,4,1,in);
	}

	// now read triange definitions
	model->triangle = new (unsigned)[model->num_triangles*4];

	for(i=0;i<model->num_triangles;i++)
	{
		fread(model->triangle+i*4,4,1,in);
		fread(model->triangle+i*4+1,4,1,in);
		fread(model->triangle+i*4+2,4,1,in);
		fread(model->triangle+i*4+3,4,1,in);

	}

	// now read the frames
	model->frame = new (struct MDL_frame)[model->num_frames];

	tx=wherex();
	ty=wherey();

	for(k=0; k<model->num_frames;  k++)
	{
		fread(&model->frame[k].type,4,1,in);
		// if single frames

		if(model->frame[k].type==0)
		{
			gotoxy(tx,ty);
			printf("reading frame %d : ",k );
			fread(&model->frame[k].sframe.bboxmin,1,4,in);
			fread(&model->frame[k].sframe.bboxmax,1,4,in);
			fread(model->frame[k].sframe.name,16,1,in);
			printf("%s \n",model->frame[k].sframe.name );
			model->frame[k].sframe.tv = new (trivertex)[model->num_vertices];

			for(i=0;i<model->num_vertices;i++)
			{
				fread(model->frame[k].sframe.tv+i,1,4,in);
			}
		}
		else
		{

			gotoxy(tx,ty);
			printf("reading group %d :",k );
			fread(&model->frame[k].gframe.num_gsframes,1,4,in);
			fread(&model->frame[k].gframe.bboxmin,1,4,in);
			fread(&model->frame[k].gframe.bboxmax,1,4,in);
			model->frame[k].gframe.gsframe_interval = new (float)[model->frame[k].gframe.num_gsframes];
			model->frame[k].gframe.gsframe = new (MDL_model_frame)[model->frame[k].gframe.num_gsframes];
			for(j=0; j<model->frame[k].gframe.num_gsframes; j++)
			{
				fread(&model->frame[k].gframe.gsframe_interval[j],4,1,in);
			}

			for(j=0; j<model->frame[k].gframe.num_gsframes; j++)
			{
				fread(&model->frame[k].gframe.gsframe[j].bboxmin,1,4,in);
				fread(&model->frame[k].gframe.gsframe[j].bboxmax,1,4,in);
				fread(model->frame[k].gframe.gsframe[j].name,16,1,in);
				model->frame[k].gframe.gsframe[j].tv = new (trivertex)[model->num_vertices];
				printf(" sub frame %d : %s \n",j,model->frame[k].gframe.gsframe[j].name );

				for(i=0;i<model->num_vertices;i++)
				{
					fread(model->frame[k].gframe.gsframe[j].tv+i,1,4,in);
				}

			}


		}



	}
	// set some initial things
	model->cur_skin=0;
	model->tcolor=1;
	model->bcolor=6;
//	getch();
}



void write_mdl(FILE *out, MDL_model *model)
{

	int i,j,k;

	fwrite(&model->filetype,4,1,out);       // magic nums
	fwrite(&model->version,4,1,out);        // version 6 now
	fwrite(&model->xscale,4,1,out);         // scale = (max - mout)/255.9
	fwrite(&model->yscale,4,1,out);
	fwrite(&model->zscale,4,1,out);
	fwrite(&model->xoffset,4,1,out);        // mout
	fwrite(&model->yoffset,4,1,out);
	fwrite(&model->zoffset,4,1,out);
	fwrite(&model->radius,4,1,out);         // boundoutg radius
	fwrite(&model->eyex,4,1,out);             // eye position
	fwrite(&model->eyey,4,1,out);
	fwrite(&model->eyez,4,1,out);
	fwrite(&model->num_skins,4,1,out);      // num skins
	fwrite(&model->skinw,4,1,out);        // skin width
	fwrite(&model->skinh,4,1,out);        // skin height
	fwrite(&model->num_vertices,4,1,out);
	fwrite(&model->num_triangles,4,1,out);
	fwrite(&model->num_frames,1,4,out);
	fwrite(&model->sync_type,1,4,out);          // sync type, either 0 or random
	fwrite(&model->flags,4,1,out);          // flags
	fwrite(&model->ave_size,4,1,out);       // average size
	/// that ends the header
	// now the skin stuff
	for(k=0; k<model->num_skins; k++)
	{
		fwrite(&model->skin[k].type,4,1,out);
		if(model->skin[k].type==0)
		{
			for(j=0;j<model->skinh;j++)
			{
				for(i=0;i<model->skinw;i++)
				{
					fputc(model->skin[k].bitmap[i+model->skinw*j],out);
				}
			}

		}
		else
		{
			fwrite(&model->skin[k].num_gskins,4,1,out);
			for(j=0; j<model->skin[k].num_gskins; j++)
			{
				fwrite(&model->skin[k].gskin_interval[j],4,1,out);
			}
			for(j=0; j<model->skin[k].num_gskins; j++)
			{

				for(int jj=0;jj<model->skinh;jj++)
				{
					for(int ii=0;ii<model->skinw;ii++)
					{
						fputc(model->skin[k].gskin[j].bitmap[ii+model->skinw*jj],out);
					}
				}
			}


		}

	}

	// now the 2d vertices

	for(i=0;i<model->num_vertices;i++)
	{
		fwrite(model->vertex+i*3,4,1,out);
		fwrite(model->vertex+i*3+1,4,1,out);
		fwrite(model->vertex+i*3+2,4,1,out);
	}

	// now triangle definitions

	for(i=0;i<model->num_triangles;i++)
	{
		fwrite(model->triangle+i*4,4,1,out);
		fwrite(model->triangle+i*4+1,4,1,out);
		fwrite(model->triangle+i*4+2,4,1,out);
		fwrite(model->triangle+i*4+3,4,1,out);

	}

	// now the frames

	for(k=0; k<model->num_frames;  k++)
	{
		fwrite(&model->frame[k].type,4,1,out);
		// if single frames
		if(model->frame[k].type==0)
		{
			fwrite(&model->frame[k].sframe.bboxmin,1,4,out);
			fwrite(&model->frame[k].sframe.bboxmax,1,4,out);
			fwrite(model->frame[k].sframe.name,16,1,out);

			for(i=0;i<model->num_vertices;i++)
			{
				fwrite(model->frame[k].sframe.tv+i,1,4,out);
			}
		}
		else
		{

			fwrite(&model->frame[k].gframe.num_gsframes,1,4,out);
			fwrite(&model->frame[k].gframe.bboxmin,1,4,out);
			fwrite(&model->frame[k].gframe.bboxmax,1,4,out);
			for(j=0; j<model->frame[k].gframe.num_gsframes; j++)
			{
				fwrite(&model->frame[k].gframe.gsframe_interval[j],4,1,out);
			}

			for(j=0; j<model->frame[k].gframe.num_gsframes; j++)
			{
				fwrite(&model->frame[k].gframe.gsframe[j].bboxmin,1,4,out);
				fwrite(&model->frame[k].gframe.gsframe[j].bboxmax,1,4,out);
				fwrite(model->frame[k].gframe.gsframe[j].name,16,1,out);

				for(i=0;i<model->num_vertices;i++)
				{
					fwrite(model->frame[k].gframe.gsframe[j].tv+i,1,4,out);
				}

			}


		}



	}

}

// this routine puts quake data into a format that I like for my
// matrix routines

void setup_3d_data(MDL_model *model)
{
	int i,j,k;
	BG_3pt vect1, vect2;
	int maxn;

	// block is like a cube. a single object.
	// since each mdl frame is a single object, it is a block

	model->blocks=0;
	// get num of blocks
	for(i=0; i<model->num_frames; i++)
	{
		if(model->frame[i].type==0) model->blocks++;
		else
		{
			model->blocks+=model->frame[i].gframe.num_gsframes;
		}

	}

	model->block= new (BG_Block)[model->blocks];
	if(model->block==NULL) exit(1);

	i=0;
	int f=0;

	for(f=0; f< model->num_frames; f++)
	{
		if(model->frame[f].type==0)
		{
		model->block[i].num_pts=model->num_vertices;
		model->block[i].ptlist=new (BG_3pt)[model->block[i].num_pts+8];
		model->block[i].nindex=new (unsigned char)[model->block[i].num_pts];
		if(model->block[i].ptlist==NULL) exit(1);
		maxn=0;
		// read all points
		for(j=0;j<model->block[i].num_pts;j++)
		{
			model->block[i].ptlist[j].x=model->xscale*(model->frame[f].sframe.tv[j].v[0])+model->xoffset;//+model->f1;//+model->f1)+model->xoffset;
			model->block[i].ptlist[j].y=model->yscale*(model->frame[f].sframe.tv[j].v[1])+model->yoffset;//+model->f2;//+model->f2)+model->yoffset;
			model->block[i].ptlist[j].z=model->zscale*(model->frame[f].sframe.tv[j].v[2])+model->zoffset;//+model->f3;//+model->f3)+model->zoffset;
			model->block[i].nindex[j]=model->frame[f].sframe.tv[j].vnormal;
		}
		model->block[i].ptlist[model->block[i].num_pts].x= model->xscale*model->frame[f].sframe.bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts].y= model->yscale*model->frame[f].sframe.bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts].z= model->zscale*model->frame[f].sframe.bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+1].x= model->xscale*model->frame[f].sframe.bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+1].y= model->yscale*model->frame[f].sframe.bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+1].z= model->zscale*model->frame[f].sframe.bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+2].x= model->xscale*model->frame[f].sframe.bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+2].y= model->yscale*model->frame[f].sframe.bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+2].z= model->zscale*model->frame[f].sframe.bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+3].x= model->xscale*model->frame[f].sframe.bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+3].y= model->yscale*model->frame[f].sframe.bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+3].z= model->zscale*model->frame[f].sframe.bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+4].x= model->xscale*model->frame[f].sframe.bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+4].y= model->yscale*model->frame[f].sframe.bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+4].z= model->zscale*model->frame[f].sframe.bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+5].x= model->xscale*model->frame[f].sframe.bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+5].y= model->yscale*model->frame[f].sframe.bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+5].z= model->zscale*model->frame[f].sframe.bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+6].x= model->xscale*model->frame[f].sframe.bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+6].y= model->yscale*model->frame[f].sframe.bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+6].z= model->zscale*model->frame[f].sframe.bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+7].x= model->xscale*model->frame[f].sframe.bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+7].y= model->yscale*model->frame[f].sframe.bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+7].z= model->zscale*model->frame[f].sframe.bboxmin.v[2]+model->zoffset;



		model->block[i].num_sides=model->num_triangles;
		model->block[i].side=new (BG_Side)[model->block[i].num_sides];
		if(model->block[i].side==NULL) exit(1);

		for(j=0;j<model->block[i].num_sides; j++)
		{
			model->block[i].side[j].num_pts=3;
			if((model->block[i].side[j].pt=new(word)[3])==NULL) exit(1);

			model->block[i].side[j].pt[0]=model->triangle[j*4L+1L];
			model->block[i].side[j].pt[1]=model->triangle[j*4L+2L];
			model->block[i].side[j].pt[2]=model->triangle[j*4L+3L];
			// calc surface normals
			vect1=BG_SubtractPts(&(model->block[i].ptlist[model->block[i].side[j].pt[1]]),&(model->block[i].ptlist[model->block[i].side[j].pt[0]]));
			vect2=BG_SubtractPts(&(model->block[i].ptlist[model->block[i].side[j].pt[2]]),&(model->block[i].ptlist[model->block[i].side[j].pt[1]]));
			model->block[i].side[j].normal=BG_CrossProduct(&vect2,&vect1);
			BG_Normalize(&(model->block[i].side[j].normal));
		}
		model->block[i].name=model->frame[f].sframe.name;
		i++;
		}

		// if group frame
		else
		{

		for(int ii=0; ii<model->frame[f].gframe.num_gsframes; ii++)
		{
		model->block[i].num_pts=model->num_vertices;
		model->block[i].ptlist=new (BG_3pt)[model->block[i].num_pts+8];
		model->block[i].nindex=new (unsigned char)[model->block[i].num_pts];
		if(model->block[i].ptlist==NULL) exit(1);
		maxn=0;
		// read all points
		for(j=0;j<model->block[i].num_pts;j++)
		{
			model->block[i].ptlist[j].x=model->xscale*(model->frame[f].gframe.gsframe[ii].tv[j].v[0])+model->xoffset;//+model->f1;//+model->f1)+model->xoffset;
			model->block[i].ptlist[j].y=model->yscale*(model->frame[f].gframe.gsframe[ii].tv[j].v[1])+model->yoffset;//+model->f2;//+model->f2)+model->yoffset;
			model->block[i].ptlist[j].z=model->zscale*(model->frame[f].gframe.gsframe[ii].tv[j].v[2])+model->zoffset;//+model->f3;//+model->f3)+model->zoffset;
			model->block[i].nindex[j]=model->frame[f].gframe.gsframe[ii].tv[j].vnormal;
		}
		model->block[i].ptlist[model->block[i].num_pts].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+1].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+1].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+1].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+2].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+2].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+2].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+3].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+3].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+3].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+4].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+4].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+4].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+5].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+5].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+5].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+6].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+6].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+6].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[2]+model->zoffset;

		model->block[i].ptlist[model->block[i].num_pts+7].x= model->xscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[0]+model->xoffset;
		model->block[i].ptlist[model->block[i].num_pts+7].y= model->yscale*model->frame[f].gframe.gsframe[ii].bboxmax.v[1]+model->yoffset;
		model->block[i].ptlist[model->block[i].num_pts+7].z= model->zscale*model->frame[f].gframe.gsframe[ii].bboxmin.v[2]+model->zoffset;



		model->block[i].num_sides=model->num_triangles;
		model->block[i].side=new (BG_Side)[model->block[i].num_sides];
		if(model->block[i].side==NULL) exit(1);

		for(j=0;j<model->block[i].num_sides; j++)
		{
			model->block[i].side[j].num_pts=3;
			if((model->block[i].side[j].pt=new(word)[3])==NULL) exit(1);

			model->block[i].side[j].pt[0]=model->triangle[j*4L+1L];
			model->block[i].side[j].pt[1]=model->triangle[j*4L+2L];
			model->block[i].side[j].pt[2]=model->triangle[j*4L+3L];
			// calc surface normals
			vect1=BG_SubtractPts(&(model->block[i].ptlist[model->block[i].side[j].pt[1]]),&(model->block[i].ptlist[model->block[i].side[j].pt[0]]));
			vect2=BG_SubtractPts(&(model->block[i].ptlist[model->block[i].side[j].pt[2]]),&(model->block[i].ptlist[model->block[i].side[j].pt[1]]));
			model->block[i].side[j].normal=BG_CrossProduct(&vect2,&vect1);
			BG_Normalize(&(model->block[i].side[j].normal));
		}
		model->block[i].name=model->frame[f].gframe.gsframe[ii].name;
		i++;
		}
		}
	}
}
// clean up data

void delete_3d_data(MDL_model *mdl)
{
/*	int i,j,blocks;

	blocks=mdl->num_frames;

	for(i=0; i<blocks; i++)
	{
		delete [] block[i].ptlist;

		for(j=0;j<block[i].num_sides; j++)
		{
			delete [] block[i].side[j].pt;
		}
		delete [] block[i].side;
	}

	delete [] block;
*/
}
