/* 
	name: getworld.c

	Input handler
	-------------
	
	This part will read and interpret a scene description file.


 */


#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>

#include  "defs.h"
#include  "getworld.h"
#include  "extern.h"


	TEXTURE		DefaultTexture;
	TRANSFORM	DefaultTransform;


/*****************************************************************
 *
 *      This is the main imput routine
 *
 *****************************************************************/


int CreateWorld(char *filename )
{
	int	RetOK=0,EndReached=-1;
	char	strtmp[100];
	FILE	*parfile;

	NumObjects=NumLights=0;
	SetupDefaults();

	if((parfile=fopen(filename,"r"))!=0) {
	    fprintf(stderr,"\nBuilding scene\n[");
	    while((EndReached!=0)&&(RetOK==0)&&(getnextkeyword(parfile,strtmp)==0)) {
		if(strcmp(strtmp,(char *)"PLANE:")==0)
		    RetOK=InitNewPlane(parfile);
		else if(strcmp(strtmp,(char *)"SPHERE:")==0)
		    RetOK=InitNewSphere(parfile);
		else if(strcmp(strtmp,(char *)"ELLIPSOID:")==0)
		    RetOK=InitNewEllipsoid(parfile);
		else if(strcmp(strtmp,(char *)"TRIANGLE:")==0)
		    RetOK=InitNewTriangle(parfile);
		else if(strcmp(strtmp,(char *)"BOX:")==0)
		    RetOK=InitNewBox(parfile);
		else if(strcmp(strtmp,(char *)"DISC:")==0)
		    RetOK=InitNewDisc(parfile);
		else if(strcmp(strtmp,(char *)"CYLINDER:")==0)
		    RetOK=InitNewCylinder(parfile);
		else if(strcmp(strtmp,(char *)"LIGHT:")==0)
		    RetOK=InitNewLight(parfile);
		else if(strcmp(strtmp,(char *)"CAMERA:")==0)
		    RetOK=InitCamera(parfile);
		else if(strcmp(strtmp,(char *)"GLOBALS:")==0)
		    RetOK=InitGlobals(parfile);
		else if(strcmp(strtmp,(char *)"DEFTEXTURE:")==0)
		    RetOK=InitTexture(&DefaultTexture,parfile);
		else if(strcmp(strtmp,(char *)"DEFTRANSFORM:")==0)
		    RetOK=InitTransform(&DefaultTransform,parfile);
		else if(strcmp(strtmp,(char *)"END")==0) {
		    EndReached=0;
		}
		else {
			fprintf(stderr,"\n\nError: Unknown keyword \"%s\"",strtmp);
			RetOK=-1;
		}
	    }
	    fprintf(stderr,"]\n\n");
	    if(NumObjects<=0) {
	    	fprintf(stderr,"No objects were declared!\n");
	    	RetOK=-1;
	    }
	    if(NumLights<=0) {
	    	fprintf(stderr,"No lights were declared!\n");
	    	RetOK=-1;
	    }
	    if(RetOK!=0) fprintf(stderr,"*** Failed!\n\n");
	    fclose(parfile);
	}
	else {
		RetOK=-1;
		fprintf(stderr,"\n*** Could not open description file!\n");
	}
	return(RetOK);
}



/*****************************************************************
 *
 *      Initialization routines
 *
 *****************************************************************/


int InitNewPlane(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	PLANE	TmpPlane, *NewPlane;
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  TmpPlane.Normal.x=0.0;	/* Set default values */
	  TmpPlane.Normal.y=0.0;
	  TmpPlane.Normal.z=1.0;
	  TmpPlane.a=0.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"NORMAL")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpPlane.Normal.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpPlane.Normal.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpPlane.Normal.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"OFFSET")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpPlane.a,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown plane-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewPlane=(PLANE *)malloc(sizeof(PLANE)))!=NULL) {
			CopyVector(&NewPlane->Normal,&TmpPlane.Normal);
			NewPlane->a=TmpPlane.a;

			NewObject->ShapeType=SHAPE_PLANE;
			NewObject->Shape=NewPlane;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new plane\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}


int InitNewSphere(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	SPHERE	TmpSphere, *NewSphere;
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  TmpSphere.Centre.x=0.0;	/* Set default values */
	  TmpSphere.Centre.y=0.0;
	  TmpSphere.Centre.z=0.0;
	  TmpSphere.r=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"CENTRE")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpSphere.Centre.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpSphere.Centre.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpSphere.Centre.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"RADIUS")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpSphere.r,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown sphere-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewSphere=(SPHERE *)malloc(sizeof(SPHERE)))!=NULL) {
			CopyPoint(&NewSphere->Centre,&TmpSphere.Centre);
			NewSphere->r=TmpSphere.r;

			NewObject->ShapeType=SHAPE_SPHERE;
			NewObject->Shape=NewSphere;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new sphere\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}



int InitNewEllipsoid(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	ELLIPSOID	TmpEllipsoid, *NewEllipsoid;
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  TmpEllipsoid.Centre.x=0.0;	/* Set default values */
	  TmpEllipsoid.Centre.y=0.0;
	  TmpEllipsoid.Centre.z=0.0;
	  TmpEllipsoid.Radius.x=1.0;
	  TmpEllipsoid.Radius.y=1.0;
	  TmpEllipsoid.Radius.z=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"CENTRE")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpEllipsoid.Centre.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpEllipsoid.Centre.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpEllipsoid.Centre.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"RADIUS")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpEllipsoid.Radius.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpEllipsoid.Radius.y,dtmp,mincoord,maxcoord,strtmp);
			if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpEllipsoid.Radius.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown ellipsoid-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewEllipsoid=(ELLIPSOID *)malloc(sizeof(ELLIPSOID)))!=NULL) {
			CopyPoint(&NewEllipsoid->Centre,&TmpEllipsoid.Centre);
			CopyVector(&NewEllipsoid->Radius,&TmpEllipsoid.Radius);

			NewObject->ShapeType=SHAPE_ELLIPSOID;
			NewObject->Shape=NewEllipsoid;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new ellipsoid\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}



int InitNewTriangle(FILE *parfile)
{
	double	dtmp,maxx,maxy,maxz,minx,miny,minz;
	char	strtmp[100];
	TRIANGLE  *NewTriangle;
	TRANSFORM TmpTransform;
	POINT	Corners[3];
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	VECTOR	v1,v2,n;
	int	RetOK=0,EndReached=-1,i;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  Corners[0].x=0.0;			/* Set default values */
	  Corners[0].y=0.0;
	  Corners[0].z=0.0;
	  Corners[1].x=1.0;
	  Corners[1].y=1.0;
	  Corners[1].z=1.0;
	  Corners[2].x=-1.0;
	  Corners[2].y=1.0;
	  Corners[2].z=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"CORNERS")==0) {
		    i=0;
		    while((i<3)&&(EndReached!=0)) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
			i++;
		    }
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown triangle-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewTriangle=(TRIANGLE *)malloc(sizeof(TRIANGLE)))!=NULL) {
			for(i=0;i<3;i++) {
				CopyPoint(&NewTriangle->Corners[i],&Corners[i]);
			}
			v1.x=Corners[1].x-Corners[0].x;
			v1.y=Corners[1].y-Corners[0].y;
			v1.z=Corners[1].z-Corners[0].z;
			v2.x=Corners[2].x-Corners[0].x;
			v2.y=Corners[2].y-Corners[0].y;
			v2.z=Corners[2].z-Corners[0].z;
			CrossProduct(&n,&v1,&v2);
			CopyVector(&NewTriangle->Plane.Normal,&n);
			NewTriangle->Plane.a=Corners[0].x*n.x+Corners[0].y*n.y+Corners[0].z*n.z;

			minx=maxx=Corners[0].x;				/* Calculate min/max boundaries for x,y,z... */
			miny=maxy=Corners[0].y;				/* This significantly speeds up the checking */
			minz=maxz=Corners[0].z;				/* for ray-intersections.                    */
			if(Corners[1].x>maxx) maxx=Corners[1].x;
			else if(Corners[1].x<minx) minx=Corners[1].x;
			if(Corners[2].x>maxx) maxx=Corners[2].x;
			else if(Corners[2].x<minx) minx=Corners[2].x;
			if(Corners[1].y>maxy) maxy=Corners[1].y;
			else if(Corners[1].y<miny) miny=Corners[1].y;
			if(Corners[2].y>maxy) maxy=Corners[2].y;
			else if(Corners[2].y<miny) miny=Corners[2].y;
			if(Corners[1].z>maxz) maxz=Corners[1].z;
			else if(Corners[1].z<minz) minz=Corners[1].z;
			if(Corners[2].z>maxz) maxz=Corners[2].z;
			else if(Corners[2].z<minz) minz=Corners[2].z;
			NewTriangle->Min.x=minx; NewTriangle->Max.x=maxx;
			NewTriangle->Min.y=miny; NewTriangle->Max.y=maxy;
			NewTriangle->Min.z=minz; NewTriangle->Max.z=maxz;

			NewObject->ShapeType=SHAPE_TRIANGLE;
			NewObject->Shape=NewTriangle;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new triangle\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}



int InitNewBox(FILE *parfile)
{
	double	dtmp,maxx,maxy,maxz,minx,miny,minz;
	char	strtmp[100];
	BOX	*NewBox;
	POINT	Corners[2];
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1,i;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  Corners[0].x=0.0;			/* Set default values */
	  Corners[0].y=0.0;
	  Corners[0].z=0.0;
	  Corners[1].x=1.0;
	  Corners[1].y=1.0;
	  Corners[1].z=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"CORNERS")==0) {
		    i=0;
		    while((i<2)&&(EndReached!=0)) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Corners[i].z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
			i++;
		    }
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown box-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewBox=(BOX *)malloc(sizeof(BOX)))!=NULL) {
			CreateVector(&NewBox->Planes[0].Normal,-1.0,0.0,0.0);
			CreateVector(&NewBox->Planes[1].Normal,1.0,0.0,0.0);
			CreateVector(&NewBox->Planes[2].Normal,0.0,-1.0,0.0);
			CreateVector(&NewBox->Planes[3].Normal,0.0,1.0,0.0);
			CreateVector(&NewBox->Planes[4].Normal,0.0,0.0,-1.0);
			CreateVector(&NewBox->Planes[5].Normal,0.0,0.0,1.0);
			
			minx=maxx=Corners[0].x;				/* Calculate min/max boundaries for x,y,z...    */
			miny=maxy=Corners[0].y;				/* This is so that you can give the coordinates */
			minz=maxz=Corners[0].z;				/* in any order.                                */
			if(Corners[1].x>maxx) maxx=Corners[1].x;
			else if(Corners[1].x<minx) minx=Corners[1].x;
			if(Corners[1].y>maxy) maxy=Corners[1].y;
			else if(Corners[1].y<miny) miny=Corners[1].y;
			if(Corners[1].z>maxz) maxz=Corners[1].z;
			else if(Corners[1].z<minz) minz=Corners[1].z;

			NewBox->Planes[0].a=-minx;
			NewBox->Planes[1].a=maxx;
			NewBox->Planes[2].a=-miny;
			NewBox->Planes[3].a=maxy;
			NewBox->Planes[4].a=-minz;
			NewBox->Planes[5].a=maxz;

			CreatePoint(&NewBox->Corners[0],minx,miny,minz);
			CreatePoint(&NewBox->Corners[1],maxx,maxy,maxz);

			NewObject->ShapeType=SHAPE_BOX;
			NewObject->Shape=NewBox;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new box\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}


int InitNewDisc(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	DISC	TmpDisc, *NewDisc;
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  TmpDisc.Plane.Normal.x=0.0;	/* Set default values */
	  TmpDisc.Plane.Normal.y=0.0;
	  TmpDisc.Plane.Normal.z=1.0;
	  TmpDisc.Plane.a=0.0;
	  TmpDisc.r=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"NORMAL")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Plane.Normal.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Plane.Normal.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Plane.Normal.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"CENTRE")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Centre.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Centre.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpDisc.Centre.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"RADIUS")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpDisc.r,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown disc-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewDisc=(DISC *)malloc(sizeof(DISC)))!=NULL) {
			CopyPoint(&NewDisc->Centre,&TmpDisc.Centre);
			NewDisc->r=TmpDisc.r;
			CopyVector(&NewDisc->Plane.Normal,&TmpDisc.Plane.Normal);
			NewDisc->Plane.a=(TmpDisc.Plane.Normal.x*TmpDisc.Centre.x+TmpDisc.Plane.Normal.y*TmpDisc.Centre.y+TmpDisc.Plane.Normal.z*TmpDisc.Centre.z);

			NewObject->ShapeType=SHAPE_DISC;
			NewObject->Shape=NewDisc;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new disc\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}



int InitNewCylinder(FILE *parfile)
{
	double	dtmp,nx,ny,nz;
	char	strtmp[100];
	CYLINDER	TmpCyl, *NewCyl;
	OBJECT	*NewObject;
	TEXTURE	TmpText;
	TRANSFORM TmpTransform;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumObjects>=maxobjects) {
		fprintf(stderr,"\n*** Maximum amount of objects exceeded!\n");
		RetOK=-1;
	}

	else {
	  CopyTexture(&TmpText,&DefaultTexture);
	  CopyTransform(&TmpTransform,&DefaultTransform);

	  CreatePoint(&TmpCyl.Ends[0],0.0,0.0,0.0);
	  CreatePoint(&TmpCyl.Ends[1],0.0,0.0,1.0);
	  TmpCyl.r=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"HEIGHT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&TmpCyl.Ends[1].z,dtmp,mincoord,maxcoord,strtmp);
				TmpCyl.Ends[0].x=TmpCyl.Ends[0].y=TmpCyl.Ends[0].z=TmpCyl.Ends[1].x=TmpCyl.Ends[1].y=0.0;
			}
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"START")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[0].x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[0].y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[0].z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"END")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[1].x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[1].y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpCyl.Ends[1].z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"RADIUS")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpCyl.r,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TEXTURE:")==0) {
			RetOK=InitTexture(&TmpText,parfile);
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			RetOK=InitTransform(&TmpTransform,parfile);
			AddTransform(&TmpText.Transform,&TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown cylinder-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewObject=(OBJECT *)malloc(sizeof(OBJECT)))!=NULL) {
		if((NewCyl=(CYLINDER *)malloc(sizeof(CYLINDER)))!=NULL) {
			CopyPoint(&NewCyl->Ends[0],&TmpCyl.Ends[0]);
			CopyPoint(&NewCyl->Ends[1],&TmpCyl.Ends[1]);
			CopyPoint(&NewCyl->Discs[1].Centre,&TmpCyl.Ends[1]);
			CopyPoint(&NewCyl->Discs[0].Centre,&TmpCyl.Ends[0]);
			NewCyl->Discs[0].r=TmpCyl.r;
			NewCyl->Discs[1].r=TmpCyl.r;
			CreateVector(&NewCyl->Discs[1].Plane.Normal,TmpCyl.Ends[1].x-TmpCyl.Ends[0].x,TmpCyl.Ends[1].y-TmpCyl.Ends[0].y,TmpCyl.Ends[1].z-TmpCyl.Ends[0].z);
			NegVector(&NewCyl->Discs[0].Plane.Normal,&NewCyl->Discs[1].Plane.Normal);
			nx=NewCyl->Discs[0].Plane.Normal.x*NewCyl->Discs[0].Centre.x;
			ny=NewCyl->Discs[0].Plane.Normal.y*NewCyl->Discs[0].Centre.y;
			nz=NewCyl->Discs[0].Plane.Normal.z*NewCyl->Discs[0].Centre.z;
			NewCyl->Discs[0].Plane.a=nx+ny+nz;	
			nx=NewCyl->Discs[1].Plane.Normal.x*NewCyl->Discs[1].Centre.x;
			ny=NewCyl->Discs[1].Plane.Normal.y*NewCyl->Discs[1].Centre.y;
			nz=NewCyl->Discs[1].Plane.Normal.z*NewCyl->Discs[1].Centre.z;
			NewCyl->Discs[1].Plane.a=nx+ny+nz;	
			NewCyl->r=TmpCyl.r;

			NewObject->ShapeType=SHAPE_CYLINDER;
			NewObject->Shape=NewCyl;
			CopyTexture(&NewObject->Texture,&TmpText);
			CopyTransform(&NewObject->Transform,&TmpTransform);

			ObjectArray[NumObjects]=NewObject;
			NumObjects++;
		}
		else {
			fprintf(stderr,"\nError: Could not allocate memory for new cylinder\n");
			free(NewObject);
			RetOK=-1;
		}
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new object\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}



int InitNewLight(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	LIGHT	TmpLight, *NewLight;
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(NumLights>=maxlights) {
		fprintf(stderr,"\n*** Maximum amount of lights exceeded!\n");
		RetOK=-1;
	}

	else {
	  TmpLight.Location.x=10.0;		/* Set default values */
	  TmpLight.Location.y=-10.0;
	  TmpLight.Location.z=10.0;
	  TmpLight.Color.r=TmpLight.Color.g=TmpLight.Color.b=1.0;

	  if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"LOCATION")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpLight.Location.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpLight.Location.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpLight.Location.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"COLOR")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpLight.Color.r,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpLight.Color.g,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&TmpLight.Color.b,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown light-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	  }

	  if(RetOK==0) {
	    if((NewLight=(LIGHT *)malloc(sizeof(LIGHT)))!=NULL) {
		CopyPoint(&NewLight->Location,&TmpLight.Location);
		NewLight->Color.r=TmpLight.Color.r;
		NewLight->Color.g=TmpLight.Color.g;
		NewLight->Color.b=TmpLight.Color.b;
		LightArray[NumLights]=NewLight;
		NumLights++;
	    }
	    else {
		fprintf(stderr,"\nError: Could not allocate memory for new light\n");
		RetOK=-1;
	    }
	  }
	}
	return(RetOK);
}




int InitCamera(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");

	if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"LOCATION")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Camera.Location.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Camera.Location.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&Camera.Location.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"VIEWPOINT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.ViewPoint.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.ViewPoint.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.ViewPoint.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"ASPECT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.Aspect.x,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.Aspect.y,dtmp,mincoord,maxcoord,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
		    		set_dvalue(&Camera.Aspect.z,dtmp,mincoord,maxcoord,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown camera-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	}
	if(RetOK==0)
		CreateCamera(&Camera, &Camera.Location, &Camera.ViewPoint, &Camera.Aspect);

	return(RetOK);
}



int InitTexture(TEXTURE *TmpTexture, FILE *parfile)
{
	double	dtmp,d2tmp;
	char	strtmp[100],strtmp2[100];
	int	RetOK=0,EndReached=-1;
	long	lastbound,i;

/*	fprintf(stderr,"."); */

/*	CopyTransform(&TmpTexture->Transform,&DefaultTransform); */

	if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"COLOR")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[0].r=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[0].g=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[0].b=d2tmp;
			}
		    	else EndReached=0L;
			TmpTexture->CMap.Colors[1].r=TmpTexture->CMap.Colors[1].g=TmpTexture->CMap.Colors[1].b=0.0;
			TmpTexture->CMap.Bounds[0]=0.0;
			TmpTexture->CMap.Bounds[1]=1.0;
			TmpTexture->CMap.LastBound=1;
		}
		else if(strcmp(strtmp,(char *)"COLORMAP")==0) {
	    	    if(getnextnumber(parfile,&dtmp)==0)
			set_ivalue(&lastbound,(long)floor(dtmp),1,10,strtmp);
		    lastbound--;
		    i=0;
		    while((i<=lastbound)&&(EndReached!=0)) {
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Bounds[i]=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[i].r=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[i].g=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,0.0,1.0,strtmp);
				TmpTexture->CMap.Colors[i].b=d2tmp;
				i++;
			}
		    	else EndReached=0L;
		    }
		    TmpTexture->CMap.LastBound=i;
		}
		else if(strcmp(strtmp,(char *)"PATTERN")==0) {
			if(getnextkeyword(parfile,strtmp2)==0) {
				if(strcmp(strtmp2,(char *)"NONE")==0)
				    TmpTexture->Pattern=PATTERN_NONE;
				else if(strcmp(strtmp2,(char *)"CHECKER")==0)
				    TmpTexture->Pattern=PATTERN_CHECKER;
				else if(strcmp(strtmp2,(char *)"CIRCLES")==0)
				    TmpTexture->Pattern=PATTERN_CIRCLES;
				else if(strcmp(strtmp2,(char *)"RINGS")==0)
				    TmpTexture->Pattern=PATTERN_RINGS;
				else if(strcmp(strtmp2,(char *)"SPOTS")==0)
				    TmpTexture->Pattern=PATTERN_SPOTS;
				else if(strcmp(strtmp2,(char *)"GRADIENT")==0)
				    TmpTexture->Pattern=PATTERN_GRADIENT;
				else {
				    fprintf(stderr,"\nError: Unknown pattern identifier \"%s\"\n",strtmp2);
				    RetOK=-1;
				}
			}
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"REFLECT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Reflect.r,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Reflect.g,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Reflect.b,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"FILTER")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Filter.r,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Filter.g,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Filter.b,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"IOR")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Ior,dtmp,1.0,2.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"AMBIENT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Ambient,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"DIFFUSE")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Diffuse,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"PHONG")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->Phong,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"PHONGSIZE")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&TmpTexture->PhongSize,dtmp,0.0,100.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"TRANSFORM:")==0) {
			InitTransform(&TmpTexture->Transform,parfile);
		}
		else if(strcmp(strtmp,(char *)"DEFAULT")==0) {
			CreateDefTexture(TmpTexture);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown texture-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	}

	return(RetOK);
}



int InitTransform(TRANSFORM *TmpTransform, FILE *parfile)
{
	double	dtmp,d2tmp;
	char	strtmp[100];
	int	RetOK=0,EndReached=-1;
	long	numtransforms;

/*	fprintf(stderr,"."); */

	numtransforms=TmpTransform->NumTransforms;

	if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(numtransforms>=10) {
			fprintf(stderr,"\n*** Maximum amount of transforms exceeded\n");
			RetOK=-1;
		}
		else if(strcmp(strtmp,(char *)"SCALE")==0) {
			TmpTransform->Entry[numtransforms].Type=TRANSFORM_SCALE;
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,EPSILON,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.x=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,EPSILON,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.y=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,EPSILON,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.z=d2tmp;
			}
		    	else EndReached=0L;
			if((TmpTransform->Entry[numtransforms].Values.x!=1.0)||(TmpTransform->Entry[numtransforms].Values.y!=1.0)||(TmpTransform->Entry[numtransforms].Values.z!=1.0))
				numtransforms++;
		}
		else if(strcmp(strtmp,(char *)"MOVE")==0) {
			TmpTransform->Entry[numtransforms].Type=TRANSFORM_MOVE;
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,mincoord,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.x=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,mincoord,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.y=d2tmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,mincoord,maxcoord,strtmp);
				TmpTransform->Entry[numtransforms].Values.z=d2tmp;
			}
		    	else EndReached=0L;
			if((TmpTransform->Entry[numtransforms].Values.x!=0.0)||(TmpTransform->Entry[numtransforms].Values.y!=0.0)||(TmpTransform->Entry[numtransforms].Values.z!=0.0))
				numtransforms++;
		}
		else if(strcmp(strtmp,(char *)"ROTATE")==0) {
			TmpTransform->Entry[numtransforms].Type=TRANSFORM_ROTATE;
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,-99999.0,99999.0,strtmp);
				dtmp=fmod(d2tmp,360.0)*RADPDEG;		/* Transform from degrees to radians */
				TmpTransform->Entry[numtransforms].Values.x=dtmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,-99999.0,99999.0,strtmp);
				dtmp=fmod(d2tmp,360.0)*RADPDEG;
				TmpTransform->Entry[numtransforms].Values.y=dtmp;
			}
	    		if(getnextnumber(parfile,&dtmp)==0) {
				set_dvalue(&d2tmp,dtmp,-99999.0,99999.0,strtmp);
				dtmp=fmod(d2tmp,360.0)*RADPDEG;
				TmpTransform->Entry[numtransforms].Values.z=dtmp;
			}
		    	else EndReached=0L;
			if((TmpTransform->Entry[numtransforms].Values.x!=0.0)||(TmpTransform->Entry[numtransforms].Values.y!=0.0)||(TmpTransform->Entry[numtransforms].Values.z!=0.0))
				numtransforms++;
		}
		else if(strcmp(strtmp,(char *)"NONE")==0) {
			ClearTransform(TmpTransform);
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown transform-keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	    if((RetOK==0)&&(EndReached==0)) {
		TmpTransform->NumTransforms=numtransforms;
	    }
	}

	return(RetOK);
}



int InitGlobals(FILE *parfile)
{
	double	dtmp;
	char	strtmp[100];
	int	RetOK=0,EndReached=-1;

	fprintf(stderr,".");


	if(getnextkeyword(parfile,strtmp)==0) {		/* Get first keyword */
	    while((EndReached!=0)&&(RetOK==0)) {
		if(strcmp(strtmp,(char *)"BACKGROUNDCOLOR")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&BackgroundColor.r,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&BackgroundColor.g,dtmp,0.0,1.0,strtmp);
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&BackgroundColor.b,dtmp,0.0,1.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"RECDEPTH")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_ivalue(&RecDepth,(long)floor(dtmp),1,50,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"PICWIDTH")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_ivalue(&PicWidth,(long)floor(dtmp),1,5000,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"PICHEIGHT")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_ivalue(&PicHeight,(long)floor(dtmp),1,5000,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"ANTIALIASREC")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_ivalue(&AntiAliasingRec,(long)floor(dtmp),0,3,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"ANTIALIASTHRESHOLD")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_dvalue(&AntiAliasingThreshold,dtmp,0.0,3.0,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)"DISPLAY")==0) {
	    		if(getnextnumber(parfile,&dtmp)==0)
				set_ivalue(&ReqDisplayType,(long)floor(dtmp),0,9999,strtmp);
		    	else EndReached=0;
		}
		else if(strcmp(strtmp,(char *)":END")==0) {
			EndReached=0;
		}
		else {
			fprintf(stderr,"\nError: Unknown globals keyword \"%s\"\n",strtmp);
			RetOK=-1;
		}
		if((RetOK==0)&&(EndReached!=0)) {
			if(getnextkeyword(parfile,strtmp)!=0) RetOK=-1;		/* Get next keyword */
		}
	    }
	}

	return(RetOK);
}



/*****************************************************************
 *
 *      Setup default globals
 *
 *****************************************************************/

void SetupDefaults(void)
{
	RecDepth=3;
	PicWidth=200; PicHeight=150;
	BackgroundColor.r=0.0; BackgroundColor.g=0.0; BackgroundColor.b=0.0;
	AntiAliasingRec=0L; AntiAliasingThreshold=0.3; AntiAliasingJitter=0.05; 
	ReqDisplayType=0L;
	
	Camera.Location.x=0.0; Camera.Location.y=-10.0; Camera.Location.z=1.0;
	Camera.ViewPoint.x=0.0; Camera.ViewPoint.y=0.0; Camera.ViewPoint.z=0.0; 
	Camera.Aspect.x=4.0; Camera.Aspect.y=3.0; Camera.Aspect.z=5.0;
	CreateCamera(&Camera, &Camera.Location, &Camera.ViewPoint, &Camera.Aspect);

	CreateDefTexture(&DefaultTexture);
	ClearTransform(&DefaultTransform);
}



/*****************************************************************
 *
 *      Miscellanous subroutines
 *
 *****************************************************************/


/*
 *                          ----------
 *                         *-- NOTE --*
 *                          ----------
 *
 * These routines may have to be changed if your system uses a
 * non-ascii standard. Sorry about that, but I guess most systems
 * ARE ascii today...
 *
 */


int ischar(int a)
{
	int	b;

	b=-1;
	if((a>=33)&&(a<=126)) b=0;		/* chr(a) = "!..~" (all chars) */
	return(b);
}

int isletter(int *a)
{
	int	b;

	b=-1;
	if((*a>=(int)'a')&&(*a<=(int)'z')) *a=*a-(int)'a'+(int)'A';	/* Make uppercase */
	if(((*a>=(int)'A')&&(*a<=(int)'Z'))||(*a==(int)':')) b=0;	/* chr(a) = "A..Z" or ":" */

	return(b);
}

int isnumber(int a)
{
	int	b;

	b=-1;
	if(((a>=(int)'0')&&(a<=(int)'9'))||(a==(int)'-')||(a==(int)'.')) b=0;	/* chr(a) = "0..9" or "-" or "." */
	return(b);
}

int iscomment(int a)
{
	int	b;

	b=-1;
	if((a==(int)'#')||(a==(int)';')||(a==(int)'*')) b=0;
	return(b);
}


int isnewline(int a)
{
	int	b;

	b=-1;
	if((a==(int)10)||(a==(int)13)) b=0;
	return(b);
}


int getnextkeyword(FILE *f, char *keyword)
{
	int	itmp,i;

	i=0;
	keyword[0]=(char) 0;
	itmp=fgetc(f);
	while((itmp!=EOF)&&(isletter(&itmp)!=0)) {
		if(iscomment(itmp)==0) {
		    while((itmp!=EOF)&&(isnewline(itmp)!=0)) {
			itmp=fgetc(f);
		    }
		}
		itmp=fgetc(f);
	}
	while((itmp!=EOF)&&(isletter(&itmp)==0)&(i<99)) {
		keyword[i]=(char)itmp;
		itmp=fgetc(f);
		i++;
	}
	if(itmp==EOF) { return(-1); }
	else{
		keyword[i]=(char)0;
		return(0);
	}
}

int getnextnumber(FILE *f, double *number)
{
	int	itmp,i;
	char	string[100];

	i=0;
	string[0]=(char)"0"; string[1]=(char)0;
	itmp=fgetc(f);
	while((itmp!=EOF)&&(isnumber(itmp)!=0)) {
		if(iscomment(itmp)==0) {
		    while((itmp!=EOF)&&(isnewline(itmp)!=0)) {
			itmp=fgetc(f);
		    }
		}
		itmp=fgetc(f);
	}
	while((itmp!=EOF)&&(isnumber(itmp)==0)&&(i<99)) {
		string[i]=(char)itmp;
		itmp=fgetc(f);
		i++;
	}
	if(itmp==EOF) { return(-1); }
	else{
		string[i]=(char)0;
		*number=atof(string);
		return(0);
	}
}

void set_ivalue(long *variable, long value, long min, long max, char *string)
{
	if((value>=min)&&(value<=max)) *variable=value;
	else {
		fprintf(stderr,"\n   Warning: Invalid value for %s: %ld\n",string,value);
		if(value>max) *variable=max;
		if(value<min) *variable=min;
		fprintf(stderr,"            Set to: %ld\n",*variable);
	}
}

void set_dvalue(double *variable, double value, double min, double max, char *string)
{
	if((value>=min)&&(value<=max)) *variable=value;
	else {
		fprintf(stderr,"\n   Warning: Invalid value for %s: %lf\n",string,value);
		if(value>max) *variable=max;
		if(value<min) *variable=min;
		fprintf(stderr,"            Set to: %lf\n",*variable);
	}
}

