/*

------------------------------------------------------------------

Black Nebula

File :				3d.c
Programmer:		Colin Adams
Date:				4/3/91
Last Modified :	10/6/91

------------------------------------------------------------------

			+y
			|
			|
			|
			|
			|
			|
			|
			|
			|
			------------ +x
		  /
		 /
		/	
    /
   /
	 +z

*/


/*	---------------------------------------------------------------
		Defines/Includes
		---------------------------------------------------------------
*/

#define MAINCODE
#define AMIGA_INCLUDES

#include "3d.h"

#include <hardware/custom.h>
#include <hardware/cia.h>

#define CIAAPRA 0xBFE001 

#define FIRE   1
#define RIGHT  2
#define LEFT   4
#define DOWN   8
#define UP    16

extern struct Custom far custom;
struct CIA *cia = (struct CIA *) CIAAPRA;

extern struct RastPort my_rast_port, back_rast_port;
extern struct View my_view, back_view;
extern struct Screen *screen;
extern struct Window *window1;
extern void build_table(void), SetUpExplosions(void);
extern short U_rot, W_rot;

/*	------------------------------------------------------------------
		General Variables
		------------------------------------------------------------------
*/

char filename[80];
object myship;
short swapflag = 1;

/*	------------------------------------------------------------------
		Amiga Variables
		------------------------------------------------------------------
*/	

UWORD Palette2[] =
{
	0x0000,
	0x000F,
	0x00D7,
	0x0098,
	0x0078,
	0x0047,
	0x0016,
	0x0024,
	0x0FF0,
	0x0FB1,
	0x0F72,
	0x0C21,
	0x0803,
	0x0503,
	0x0F0F,
	0x0847 
};


/*	------------------------------------------------------------------
		EXTERNAL ROUTINES
		------------------------------------------------------------------
*/

extern object *CreateObject();


/*	------------------------------------------------------------------
		START OF ROUTINES
		------------------------------------------------------------------
*/

void CleanUpandExit(void)
/*
Frees resources and quits.  Unfortunately fails to free some memory 
somewhere, if the OS was done properly wouldn't be a problem, but I'll
try and track it down sometime.
*/
{
	EndSound();
	
	if(window1)
		CloseWindow(window1);
	if(screen)
		CloseScreen(screen);
  if(IntuitionBase)
     CloseLibrary(IntuitionBase);
  if(GfxBase)
     CloseLibrary((struct Library *) GfxBase);
  exit(1);
}

UBYTE Joystick(void)
/* 
Reads the joystick port. Goes straight to the metal...
All flames will be ignored.
*/
{
  UBYTE data = 0;
  UWORD joy;
  
	joy = custom.joy1dat;
  data += !( cia->ciapra & 0x0080 ) ? FIRE : 0;
  data += joy & 0x0002 ? RIGHT : 0;
  data += joy & 0x0200 ? LEFT : 0;
  data += (joy >> 1 ^ joy) & 0x0001 ? DOWN : 0;
  data += (joy >> 1 ^ joy) & 0x0100 ? UP : 0;

  return data;
}

UBYTE Keyboard(void)
/*
Returns the keycode of a key pressed. Goes straight to the
hardware, which isn't very nice to the OS, but is fast.
*/
{
  UBYTE code;
  code = cia->ciasdr ^ 0xFF;
  code = code & 0x01 ? (code>>1)+0x80 : code>>1;
  return code;
}

void get2d(short px, short py, short pz)
/*
Converts a point onto a 2d plane from 3d.  This code is optimized
to be fast, not readable.  The details of the algorithm are in
3d.h.  Though naturally you should be able to understand this :-)
*/
{
	register int temp;
	register int rx, ry, rz;
	
	rx = px - ex;
	ry = py - ey;
	rz = pz - ez;
	
	d = getmultC(ux, rx) + getmultC(uy, ry) + getmultC(uz,rz);

	temp = getmultC(vx, rx) + getmultC(vy, ry) + getmultC(vz,rz);
	y = d ? - (temp*571) / d : 0;

	temp = getmultC(wx, rx) + getmultC(wy, ry) + getmultC(wz,rz);
	x = (G/2) + (d ? (temp*571) / d : 0);
}

void SetUp3d(void)
/* must initialize viewing vectors */
{
	k.numer = 571; /* this variable is not used, just here for reference */
	k.denom = 1; /* because this is 1, it simplifies the calculations */
	
	ex = 4000;					 /* eye location */
	ey = 500;
	ez = 1000;
	
	setconst(vx,0);		 	/* top of skull unit vector */
	setconst(vy,1);
	setconst(vz,0);
	
	setconst(wy,0);			 /* out of right ear vector */
	SetFixed(wx, 1000,1000);
	SetFixed(wz, 0, 1000);
	
	setconst(uy,0);			 /* view vector */
	SetFixed(ux, 0, 1000);
	SetFixed(uz, -1000, 1000);
	view_mode = 0;
	View_Angle = 270;
	U_rot = 270; W_rot = 180;
}

/*	------------------------------------------------------------------
		Routines for allowing objects to be defined
		------------------------------------------------------------------
*/

void EnterObject(void)
{
	object *obj;
	polygon *pg;
	int sides, i;
	int convert;
	int x,y,z;
	
	obj = CreateObject();
	
	printf("ENTER:\n");
	printf("Enter the name of the object : ");
	scanf("%s",filename);
	strcat(filename, ".object");
	
	fflush(stdin);
	printf("Object Types:\n");
	printf("Enter the type of object : ");
	
	scanf("%d",&convert);
	obj->type = convert;
	
	printf("How many points comprise the object ? ");
	scanf("%d",&sides); /* get number points in object */
	obj->numpoints = sides;
	
	for(i=1; i<=sides; i++)
	{
		printf("Enter point %d: x, y, z = ",i);
		scanf("%d %d %d",&x,&y,&z);
		obj->objpoints[i].x = x;
		obj->objpoints[i].y = y;
		obj->objpoints[i].z = z;
	}
	
	printf("Enter the centre point of the object (x,y,z) ? ");
	scanf("%d %d %d",&x, &y, &z);
	obj->start_x = x;
	obj->start_y = y;
	obj->start_z = z;
	
	printf("Enter the approx. radius squared of the object ? ");
	scanf("%d",&x);
	obj->radius = x;
	
	printf("Enter the number of polygons : ");
	scanf("%d",&sides);
	
	for(i=0; i<sides; i++)
	{
		int numpoints, j;
		
		printf("Enter data for polygon %d :\n",i+1);
		do
		{
			printf("How many points are in this polygon ? ");
			scanf("%d",&numpoints);
		} while(numpoints>MAX_POINTS);
		
		pg = (polygon *) malloc(sizeof(polygon));

		printf("Colours :\n");
		printf("0-black, 1-blue, 2-green, 3-lt.green 4-grey, 5-med.blue\n");
		printf("6-matt.blue,7-blue/black,8-yellow,9-lt.orange,10-orange\n");
		printf("11-red,12-d.red,13-v.d.red,14-d.laven,15-lavender\n");

		printf("What colour is it ? ");
		scanf("%d", &j);
		pg->colour = j;
		
		printf("Enter %d Point Numbers : ", numpoints);
		
		for(j=0; j<numpoints; j++)
		{
			scanf("%d",&convert);
			pg->p[j] = convert;	
		}
		
		printf("Enter the centre of the polygon (x,y,z) ? ");
		scanf("%d %d %d",&x, &y, &z);
		pg->centre.x = x;
		pg->centre.y = y;
		pg->centre.z = z;
		
		pg->numpoints = numpoints;
		AddPoly(obj, pg);
	}
	
	Save_Object(obj, filename);
	Destroy_Object(obj);
}

void ChangeObjectFile(void)
{
	object *obj;
	polygon *p;
	int i, count = 1;
	int x,y,z;
		
	printf("CHANGE :\n");
	printf("Enter the object name (NO .object) - ");
	scanf("%s",filename);
	
	printf("\nObject - %s\n",filename);
	strcat(filename,".object");
	
	obj = CreateObject();
	if(!(Load_Object(obj, filename)))
		return;
	
	printf("What would you like to change ?\n");
	printf("(2=details, 1=point, 0=poly) ?");
	scanf("%d",&i);
	
	if(i==2)
	{
		printf("Current values :\n");
		printf("Type = %d\n",obj->type);
		printf("Numpoints = %d\n",obj->numpoints);
		printf("Radius = %d\n",obj->radius);
		
		printf("\nEnter type : ");
		scanf("%d", &i);
		obj->type = i;
		
		printf("Enter numpoints : ");
		scanf("%d",&i);
		obj->numpoints = i;
		
		printf("Enter radius^2 : ");
		scanf("%d",&i);
		obj->radius = i;
	
		printf("Ok.\n");
		Save_Object(obj, filename);
		Destroy_Object(obj);
		return;
	}
	
	if(i)
	{
		printf("Enter point to change (max is %d) ?",obj->numpoints);
		scanf("%d", &i);
		printf("Enter new value for point (x,y,z) ? ");
		scanf("%d %d %d", &x, &y, &z);
		obj->objpoints[i].x = x;
		obj->objpoints[i].y = y;
		obj->objpoints[i].z = z;
		printf("Ok.\n");
		Save_Object(obj, filename);
		Destroy_Object(obj);
		return;
	}
	
	printf("Enter number of polygon to change ? ");
	scanf("%d",&i);
	p = obj->poly;
	
	while(p && count!=i)
	{
		p = (polygon *) p->next;
		count++;
	}
	
	if(!p)
	{
		printf("That polygon doesn't exist!\n");
		Destroy_Object(obj);
		return;
	}
	
	printf("Old Values :\n");
	printf("  Number of points - %d\n",p->numpoints);
	printf("  Colour - %d\n",p->colour);
	printf("  Centre %d %d %d\n",p->centre.x,p->centre.y,
		p->centre.z);
		
	for(i=0; i<p->numpoints; i++)
		printf("  Point %d : %d\n",i+1,p->p[i]);
		
	printf("Enter no. of points in polygon ?");
	scanf("%d", &i);
	p->numpoints = i;
	
	printf("Colours :\n");
	printf("0-black, 1-blue, 2-green, 3-lt.green 4-grey, 5-med.blue\n");
	printf("6-matt.blue,7-blue/black,8-yellow,9-lt.orange,10-orange\n");
	printf("11-red,12-d.red,13-v.d.red,14-d.laven,15-lavender\n");
	printf("What colour is it ? ");
	scanf("%d", &i);
	p->colour = i;
	
	printf("Enter the centre of the polygon (x,y,z) ? ");
	scanf("%d %d %d", &x, &y, &z);
	p->centre.x = x;
	p->centre.y = y;
	p->centre.z = z;
	
	printf("Enter the points : ");
	
	for(i=0; i<p->numpoints; i++)
	{
			scanf("%d", &x);
			p->p[i] = x;
	}
	
	printf("Object Changed.\n");
	Save_Object(obj, filename);
	Destroy_Object(obj);
}

void PrintObjValues(void)
{
	object *obj;
	polygon *p;
	int i, counter = 1;
		
	printf("PRINT :\n");
	printf("Enter the object name (NO .object) - ");
	scanf("%s",filename);
	
	printf("\nObject - %s\n",filename);
	strcat(filename,".object");
	
	obj = CreateObject();
	if(!(Load_Object(obj, filename)))
		return;

	printf("Type - %d\n",obj->type);
	p = obj->poly;
	
	printf("Centre - %d %d %d\n",obj->start_x, obj->start_y,
		obj->start_z);

	printf("Radius - %d\n", obj->radius);
	
	printf("Points :\n");
	for(i=1; i<=obj->numpoints; i++)
	{
		printf("Point %d = %d, %d, %d\n",i,obj->objpoints[i].x,
			obj->objpoints[i].y, obj->objpoints[i].z);
	}
	
	while(p)
	{
		printf("Polygon %d :\n",counter++);
		printf("  Number of points - %d\n",p->numpoints);
		printf("  Colour - %d\n",p->colour);
		printf("  Centre %d %d %d\n",p->centre.x,p->centre.y,
			p->centre.z);
		
		for(i=0; i<p->numpoints; i++)
			printf("  Point %d : %d\n",i+1,p->p[i]);
		
		p = (polygon *) p->next;
	}
	Destroy_Object(obj);
}

void OptionMenu(void)
{
	int c;
	
	while(1)
	{
		printf("\nF-79 OBJECT CREATION\n");
		printf("Options :\n");
		printf("1 - Enter an Object\n");
		printf("2 - List Objects\n");
		printf("3 - Change Object\n");
		printf("4 - Print Object values\n");
		printf("5 - Exit\n");
		printf("Enter option : ");
		
		fflush(stdin);
		scanf("%d",&c);
		printf("\n");
		
		switch(c)
		{
			case 1:	EnterObject(); break;
			case 2:	system("dir #?.object"); break;
			case 3:	ChangeObjectFile(); break;
			case 4:	PrintObjValues(); break;
			case 5:  CleanUpandExit(); break;
			default:	printf("Unknown Option!\n");
		}		
	}
}

int main(char argc, char *argv[])
{
	IntuitionBase = (struct IntutionBase *)
		OpenLibrary("intuition.library",0);
	
	if(IntuitionBase==NULL)
		exit(FALSE);
	
	GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library",0);
	
	if(GfxBase==NULL)
		CleanUpandExit();

	TrigSetUp();	/* set up fast sin/cos table */
	build_table(); /* set up fast square root table */
	Setupangles(); /* set up fast asin table */

	
	if(argc>=2)
		OptionMenu();
	else
	{
		SoundSetUp();  /* load sound effects */
		SetRandom();
		SetUpExplosions();
		DoIntro();
	}
	
	CleanUpandExit();
}

/* end of module 3d.c */
