//
// 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"

int mdl_keys(MDL_model *);
void load_model(char *, MDL_model *);
void vline (unsigned char *, int *, int *,MDL_model );
MDL_window win2d, win3d;
// use this stuff for command line options
#define NUM_CFG_OPTIONS 3
char *cfg_option[NUM_CFG_OPTIONS] = {"mode","driver","progspath"};
char driver[128], progspath[128];
unsigned char pal[256*3];
unsigned char cmap[256*32];
//GrContext *BitMapContext;
void OpenColorMap(char *,unsigned char *);

//----------------------------------------------------------------------

int main (int argc, char *argv[])
{
	FILE *in, *out, *qpal;
	unsigned char bmppal[256*3];
	unsigned bmpw, bmph;
	struct MDL_model model;
	char *in_filename,*out_filename,*filename;
	char str[256];
	char ch;
	short cur_key;
	short draw_3d=1;
	short draw_triangles=0;
	short draw_vertices=0;
	short import_bmpfile=0;
	short export_bmpfile=0;
	short show_info=0;
	unsigned i,j,k,l;
	unsigned p1,p2,p3,p4;
	int video_mode=0;
	int update=0;
	int refresh=0;
	int oldx,oldy,oldr,oldl,oldm;
	int selected=0;
	int ontopof=0;
	int selectedx, selectedy, selectedindex;
	int madechanges=0;
	int loop;
	int goto_3d=0;
	int skin;
	float zoom_factor=2;

	// set default values
	driver[0]=NULL;
	progspath[0]=NULL;

	clrscr();
	printf("MedDLe by Brian Martin version %2.1f\n\n",VERSION);

	// get config file settings
	if((in=fopen("mdl.cfg","rt"))==NULL)
	{
		fprintf(stderr,"Can't open mdl.cfg, using defaults... \n");
		fprintf(stderr,"Things probably won't work. Hit a key. \n");
		getch();
	}
	else
	{
		fprintf(stderr,"Reading mdl.cfg ...\n");
		ch=0;
		do
		{
			fscanf(in,"%s", str);
			if(feof(in)) break;
			if(str[0]=='#') {while(fgetc(in)!=0x0A);}
			else
			{
				k=0;
				for(i=0; i<NUM_CFG_OPTIONS; i++)
				{
					j=0;
					while(*(cfg_option[i]+j)!=NULL)
					{
						k=i+1;
						if(str[j]!=*(cfg_option[i]+j)) {k=0;break;}
						j++;
					}
					if(k!=0) break;
				}
				if(k==0) fprintf(stderr,"Don't understand option \"%s\" in config file. \n",str);
				else
				{
					fscanf(in,"%s", str);
					switch (k)
					{
						case 1: video_mode=atoi(str); fprintf(stderr," - setting video mode = %d\n",video_mode); break;
						case 2: strcpy(driver,str); fprintf(stderr," - setting driver = %s\n",driver);break;
						case 3: strcpy(progspath,str); fprintf(stderr," - setting progspath = %s\n",progspath);break;
					}
				}
			}
		}while(!feof(in));
		fclose(in);
	}


	// get command line options
	for (argv++, argc--; argc && **argv == '-'; argv++, argc--)
	{
		if ((*argv)[1] == 'e' && argc-- > 1)
		{
			out_filename = *++argv;
			export_bmpfile=1;
			skin = atoi( *(++argv));

		}
		else if ((*argv)[1] == 'i' && argc-- > 1)
		{
			in_filename = *++argv;
			import_bmpfile=1;
			skin = atoi( *(++argv));
		}

		else if ((*argv)[1] == 'm' && argc-- > 1)
			video_mode= atoi( *(++argv));

		else if ((*argv)[1] == '2')
			draw_3d = 0;

		else if ((*argv)[1] == 's')
			show_info = 1;

		else if ((*argv)[1] == 'h')
		{
			fprintf(stderr, "Usage: mdl [-h] [-2] [-s] [-e <file.bmp> #] [-i <file.bmp> #] [-m #] file.mdl \n");
			fprintf(stderr, "       -h  -- help screen\n");
			fprintf(stderr, "       -2  -- start in 2d view\n");
//			fprintf(stderr, "       -s  -- show header information\n");
			fprintf(stderr, "       -e  -- extract BMP file, skin #\n");
			fprintf(stderr, "       -i  -- insert BMP file, skin #\n");
			fprintf(stderr, "       -m  -- video mode\n");
			fprintf(stderr, "              0 = 320x200 (default)\n");
			fprintf(stderr, "              1-4 hi res modes\n");
			exit(1);
		}
		else
		{
			fprintf(stderr, "What is %s?  mdl -h will help you", *argv);
			exit(1);
		}
	}

	if (argc > 0)
		filename = *argv;
	else
	{
		fprintf(stderr, "mdl -h will help you", *argv);
		exit(1);
	}

	// read in quake colors
	BG_OpenPalette("mdl.pal",pal);
	//read color map
	OpenColorMap("mdl.map",cmap);
	// read in mdl file
	// and set up data
	load_model(filename, &model);

	// export bitmap of skin
	if(export_bmpfile==1)
	{
		if((skin<=model.num_skins)&&(skin>0))
		{
			out=fopen(out_filename,"wb");
			BG_WriteBMP(out, pal, model.skin[skin-1].bitmap, model.skinw, model.skinh);
			fclose(out);
		}
		// new skin (polygon pic)
		if(skin<=0)
		{
			int x1,x2,x3;
			unsigned p1,p2,p3,p4;
			unsigned char *pic;
			pic= new(unsigned char)[model.skinw*model.skinh];

			for(j=0; j<model.skinh; j++)
			{
				for(i=0; i<model.skinw; i++)
				{
					pic[i+model.skinw*j]=0;
				}
			}

			int v1[2], v2[2];
			for(i=0;i<model.num_triangles;i++)
			{
				p1=model.triangle[i*4+1];
				p2=model.triangle[i*4+2];
				p3=model.triangle[i*4+3];
				p4=model.triangle[i*4];
				x1=x2=x3=0;
				if((model.vertex[3*p1]==32)&&(p4==0)) x1=model.skinw/2;
				if((model.vertex[3*p2]==32)&&(p4==0)) x2=model.skinw/2;
				if((model.vertex[3*p3]==32)&&(p4==0)) x3=model.skinw/2;
				v1[0]=model.vertex[p2*3+1]+x2;
				v1[1]=model.vertex[p2*3+2];
				v2[0]=model.vertex[p3*3+1]+x3;
				v2[1]=model.vertex[p3*3+2];
				vline(pic,v1,v2,model);
				v1[0]=model.vertex[p3*3+1]+x3;
				v1[1]=model.vertex[p3*3+2];
				v2[0]=model.vertex[p1*3+1]+x1;
				v2[1]=model.vertex[p1*3+2];
				vline(pic,v1,v2,model );
				v1[0]=model.vertex[p1*3+1]+x1;
				v1[1]=model.vertex[p1*3+2];
				v2[0]=model.vertex[p2*3+1]+x2;
				v2[1]=model.vertex[p2*3+2];
				vline(pic,v1,v2,model);

			}
			out=fopen(out_filename,"wb");
			BG_WriteBMP(out, pal, pic, model.skinw, model.skinh);
			fclose(out);
			delete [] pic;
		}
		goto the_end;
	}

	// import skin bmp
	if((skin>0)&&(import_bmpfile==1))
	{
		unsigned char *pic;

		in=fopen(in_filename,"rb");
		rewind(in);
		fseek(in,18,SEEK_SET);
		fread(&bmpw,4,1,in);
		fread(&bmph,4,1,in);
		fseek(in,28,SEEK_CUR);

		for (i = 0; i < 256; i++)
		{
			fread(bmppal+i*3 + 2,1,1,in);
			fread(bmppal+i*3 + 1,1,1,in);
			fread(bmppal+i*3 + 0,1,1,in);
			fseek(in,1,SEEK_CUR);
		}

		//read new pic
		pic=new (unsigned char)[(bmpw*bmph)];
		int ali;
		unsigned char junk[4];
		if(bmpw<4) ali=4-bmpw;
		else ali=bmpw%4;

		for(j=bmph;j>0;j--)
		{
			for(i=0;i<bmpw;i++)
			{
				fread(&pic[i+bmpw*(j-1)],1,1,in);
			}
			if(ali!=0) fread(&junk[0],ali,1,in);
		}
		fclose(in);

		// now stick the info in the model...
		// match colors up
		printf("matching colors\n");
		char close_color[256];
		for(i=0; i<256; i++)
		{
			close_color[i]=i;
			float error, error0=1.566e5;
			float e1,e2,e3;
			for(j=0; j<256; j++)
			{
				e1= (float)(pal[j*3]-bmppal[i*3]);
				e2= (float)(pal[j*3+1]-bmppal[i*3+1]);
				e3= (float)(pal[j*3+2]-bmppal[i*3+2]);
				error=e1*e1+e2*e2+e3*e3;
				if(error<=error0)
				{
					error0=error;
					close_color[i]=j;
				}
			}

		}

		//if adding a skin (not replacing)
		if(skin>model.num_skins)
		{
			model.num_skins++; skin=model.num_skins;
			// make room for more skin!
			struct MDL_model_skin *tempskin;
			tempskin=new(MDL_model_skin)[model.num_skins-1];
			memcpy (tempskin, model.skin,sizeof(MDL_model_skin)*(model.num_skins-1));
			delete [] model.skin;
			model.skin = new (MDL_model_skin)[model.num_skins];
			memcpy (model.skin,tempskin,sizeof(MDL_model_skin)*(model.num_skins-1));
			delete [] tempskin;
			model.skin[skin-1].bitmap=new (unsigned char)[model.skinw*model.skinh];
		}

		// resize pic if needed and add to model
		printf("resizing pic\n");
		double scalew, scaleh;
		scalew=(double)(bmpw)/(double)(model.skinw);
		scaleh=(double)(bmph)/(double)(model.skinh);

		for(j=0; j<model.skinh;j++)
		{
			for(i=0;i<model.skinw;i++)
			{
				unsigned pic_index;
				double di, dj;
				di=(double)i;
				dj=(double)j;
				pic_index=(unsigned)(scalew*di)+(unsigned)(scaleh*dj)*(bmpw);
				model.skin[skin-1].bitmap[i+j*model.skinw]=close_color[pic[pic_index]];
			}
		}

		delete [] pic;

	}



	// intiate graphics mode
	BG_GraphicsMode(driver,video_mode);
	// change the screen colors to the quake palette
	BG_SetPalette(pal);
	// initiate mouse
	BG_InitMouse();
	BG_MouseStatus();
	oldx=BG_MouseX;
	oldy=BG_MouseY;
	// intiate math tables
	BG_InitMath();

	BG_ClearScreen(0);
	// loop through the 3 modes (3d,2d,help)
	while(1)
	{
		if(draw_3d==1)
		{
			if((i=mdl_3d(&model,&win3d))==0) break;
			if(i==2) draw_3d=2;
			else draw_3d=0;
		}
		if(draw_3d==2)
		{
			if((i=mdl_keys(&model))==0) break;
			if(i==1) draw_3d=0;
			else draw_3d=1;
		}
		else
		{
			if((i=mdl_2d(&model,&win2d))==0) break;
			if(i==2) draw_3d=2;
			else draw_3d=1;
		}


	}
	// go back to text mode
	GrSetModeRestore(0);
	BG_TextMode();

	the_end:
	clrscr();



//	delete [] mdl.bitmap;
	delete[] model.vertex;
	delete [] model.triangle;
//	for(j=0; j<mdl.num_frames;  j++)
//	{
//		if(mdl.frame[j].atype!=0) delete [] mdl.frame[j].n3;
//		delete [] mdl.frame[j].v;
//	}
//	delete [] mdl.frame;
//	delete_3d_data(&mdl);

	fprintf(stderr,"\nMedDLe v%2.1f 1996\n  by Brian Martin\n  brian@phyast.pitt.edu\n  irc: ZombyWoof\n",VERSION);
	return(0);
}

// read in the color map needed for shading
void OpenColorMap(char *mapfile,unsigned char *cm)
{
	FILE *in;
	in=fopen(mapfile,"rb");

	fread(cm,1,256*32,in);
	fclose(in);

}
// help file
int mdl_keys(MDL_model *m)
{
	 int loop=1;
	 int draw_3d=2;
	 int cur_key;
	 static int page=0;
	 int MAXPAGE=5;
	 int update =1;
	 BG_ClearScreen(0);


		while(loop)
		{

			if(kbhit())
			{
				if((cur_key=getch())==0x0) cur_key=getch();
			 //	cur_key=getch();
				switch(cur_key)
				{
				case 27:	       	loop=0; draw_3d=2; break;
				case '3':			loop=0; draw_3d=1; break;
				case '2':			loop=0; draw_3d=0; break;

				case ARROW_RIGHT: case ARROW_DOWN:    if(page<MAXPAGE) page+=1;
														else page=0;
														break;
				case ARROW_LEFT: case ARROW_UP:	    if(page>0) page-=1;
														else page=MAXPAGE;
														break;

				}
				update=1;
			}

		 if(update==1)
		 {
				 BG_ClearScreen(0);
				update=0;

			if(page==0)
			{
				// page 0
				BG_Text("..About MedDLe..",BG_ScreenWidth/2-60,2,250,0);

				BG_Text("MedDLe was written by Brian Martin",5,30,253,0);
				BG_Text("   (on quake/irc I am the ZombyWoof!)",5,45,253,0);
				BG_Text("",5,60,253,0);
				BG_Text("It is free-ware and the source is included.",5,75,253,0);
				BG_Text("This is NOT an id software product! ",5,90,253,0);
				BG_Text("Questions or whatever go to:",5,105,253,0);
				BG_Text("brian@phayst.pitt.edu ",5,120,253,0);
				BG_Text("http://www.phyast.pitt.edu/~brian",5,135,253,0);
				BG_Text("",5,150,253,0);
				BG_Text("I will program for food. (i.e. hire me)",5,155,253,0);

				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}

			else if(page==1)
			{
						// page 1
				BG_Text("..MedDLe Useful Keys..",BG_ScreenWidth/2-70,2,250,0);
				BG_Text("Key  Action",5,15,250,0);
				BG_Text("1    Brings up Help",5,30,253,0);
				BG_Text("2    Brings up (2D) Skin Editor",5,45,253,0);
				BG_Text("3    Brings up (3D) Frame Editor",5,60,253,0);
				BG_Text("Esc  Exits",5,75,253,0);
				BG_Text("These keys always work. For specifics, read on.",5,90,253,0);

				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}
			else if(page==2)
			{
				// page 2
				BG_Text("..MedDLe Useful Keys..",BG_ScreenWidth/2-70,2,250,0);
				BG_Text("Keys for 2D Mode",5,15,250,0);
				BG_Text("1,3,Esc  Help, 3d mode, exit",5,30,253,0);
				BG_Text("<,>  move through skins",5,45,253,0);
				BG_Text("t    Show wireframe (triangles)",5,60,253,0);
				BG_Text("v    Show vertices",5,75,253,0);
				BG_Text("s    Saves changes",5,90,253,0);
				BG_Text(";,'  change pants",5,105,253,0);
				BG_Text("[,]  change shirt",5,120,253,0);
				BG_Text("Mouse and arrow keys move cursor",5,135,253,0);
				BG_Text("Mouse Left Button grabs vertex",5,150,253,0);

				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}
			else if(page==3)
			{
				// page 3
				BG_Text("..MedDLe Useful Keys..",BG_ScreenWidth/2-70,2,250,0);
				BG_Text("Keys for 3D Mode",5,15,250,0);
				BG_Text("1,2,Esc    Help,Skin Editor,Exit",5,30,253,0);
				BG_Text("r    Reset View",5,45,253,0);
				BG_Text("s    Save View to file 'pic#.bmp'",5,60,253,0);
				BG_Text("TAB  change render mode",5,75,253,0);
				BG_Text(";,'  change pants",5,90,253,0);
				BG_Text("[,]  change shirt",5,105,253,0);
				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}

			else if(page==4)
			{
				// page 4
				BG_Text("..MedDLe Useful Keys..",BG_ScreenWidth/2-70,2,250,0);
				BG_Text("..MORE Keys for 3D Mode",5,15,250,0);

				BG_Text("h    Show Frame Header Info",5,30,253,0);
				BG_Text("c    Cycle Through Frames",5,45,253,0);
				BG_Text("b    Change Background Color",5,60,253,0);
				BG_Text("Up/Down    Move View Up or Down",5,75,253,0);
				BG_Text("Left/Right    Cycle Frames Forward/Backward",5,90,253,0);
				BG_Text("Move Mouse moves light source",5,105,253,0);
				BG_Text("Move Mouse front/back + Right Button Zooms in/out",5,120,253,0);
				BG_Text("Move Mouse + Left Button Rotates Object",5,135,253,0);

				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}

			else if(page==5)
			{
				// page 5
				BG_Text("..MedDLe Other Info..",BG_ScreenWidth/2-70,2,250,0);

				BG_Text("Import bitmap by command line:",5,30,253,0);
				BG_Text("mdl -i player.bmp [# skin] player.mdl",5,45,253,0);
				BG_Text("  if # is bigger than num skins, adds a skin",5,60,253,0);
				BG_Text("Export bitmaps by command line:",5,60,253,0);
				BG_Text("mdl -e player.bmp [# skin] player.mdl",5,75,253,0);
				BG_Text(" if # is 0, creats a blank skin",5,90,253,0);

				BG_Text("Use arrow keys (up/down) to see more.",5,170,250,0);
			}


		 }


		}


	if(draw_3d==2) return 0;
	else if(draw_3d==1) return 2;
	else return 1;

}

void load_model(char *filename, MDL_model *model)
{
	FILE *in;
	char str[256];

	strcpy(str,progspath);
	strcat(str,filename);

	if((in=fopen(str,"rb"))==NULL)
	{
		printf("can't open mdl file \"%s\" ...exiting\n",str);
		exit(1);
	}
	read_mdl(in, model);
	fclose(in);

	strcpy(model->filename,filename);

	// setup 3d stuff
	printf("wait... setting up 3d data.\n");
	 setup_3d_data(model);

}



void vline(unsigned char *pic, int *v1, int *v2, MDL_model model)
{

			int i;
			register int inc_ah,inc_al;
			int dx,dy,long_d,short_d;
			int d,add_dh,add_dl;
			int inc_xh,inc_yh,inc_xl,inc_yl;

			dx=v2[0]-v1[0]; dy=v2[1]-v1[1];

			if(dx<0){dx=-dx; inc_xh=-1; inc_xl=-1;}
			else    {        inc_xh=1;  inc_xl=1; }

			if(dy<0){dy=-dy;inc_yh=-model.skinw;
				   inc_yl=-model.skinw;
				   }
			else    {       inc_yh= model.skinw;
				   inc_yl= model.skinw;
			}
		   if(dx>dy){long_d=dx;short_d=dy;inc_yl=0;}
			else     {long_d=dy;short_d=dx;inc_xl=0;}

			inc_ah=inc_xh+inc_yh;
			inc_al=inc_xl+inc_yl;
			pic+=v1[1]*model.skinw+v1[0];

			d=2*short_d-long_d;
			add_dl=2*short_d;
			add_dh=2*short_d-2*long_d;

			for(i=0;i<=long_d;i++)
			{
				*pic=11;
				if(d>=0){pic+=inc_ah; d+=add_dh;}
				else    {pic+=inc_al; d+=add_dl;}
			}

}