/*
 	      Gölzy's C - Ray Tracer
          letzte Version vom 04.03.1988

	nach dem PdM 11/87  >>Ray Traycer<<
	         von Thomas Graf
	         ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/

#include <stdio.h>
#include <math.h>
#include <exec/exec.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <libraries/dosextens.h>

#define INTERLACE LACE
#define M1	3
#define M2	2
#define M3	2
#define M4	8
#define MA	4
#define MG	(M1+M2+M3+M4)
#define MUL	(3-nf)
#define BREITE 320*MUL
#define HOEHE  256*MUL
#define WKLICK while((class=message(DWin))!=MOUSEBUTTONS)

VOID	Delay(),SetMenuStrip(),SetRGB4(),ShowTitle(),MoveScreen();
VOID	CloseWindow(),CloseScreen(),CloseLibrary(),Close();
VOID	SetAPen(),SetDrMd(),WritePixel(),RectFill(),Move();
VOID	FreeMem(),ReplyMsg(),RefreshGadgets(),DisplayBeep();

SHORT NR,zfarbe[85],zaehler,first,i,j,f,n,ca[4],ya,a1,a2,a3;
SHORT a4,a5,farbe,nf,px,py,nk,lq1,lq2,lq3,ff,fm,ns,nsh,kk,fh;
SHORT ku[100][5],count,title,down,kza=0,fnr,nr,x,y,xm,ym;
SHORT data[]={
	50,-50,200,200,3,
	8,10,49,8,1,
	9,43,47,14,1,
	6,17,28,6,2
};
SHORT Read(),Examine(),ExNext(),IoErr(),Text(),strlen(),atoi();
USHORT code;
ULONG class;

FLOAT bb,bh,brz,brz1,brz2,bm1,bm2,bm3,bx,br1,br2,br3,ba,bx1,bx2,bx3,cah1;
FLOAT by1,by2,by3,by,br,h1,h2,h3,ke1,ke2,ke3,kf1,kf2,kf3,kf4,kf,k,kh,cah2;
FLOAT r1,r2,r3,gf1,gf2,gf3,gf4,gf5,si,co,gh1,gh2,gh3,g1,g2,g3,gr,gg,cah3;
FLOAT bodk,s1,s2,s3,cr1,cr2,cr3,ca1,ca2,ca3,k1,k2,h,crh1,crh2,crh3;
FLOAT mbr1,mbr2,mbr3,atof();

BYTE nn[2][3]={
	(UBYTE *)"-h",
	(UBYTE *)"-l"
};
UBYTE *Men[MA]={
	(UBYTE *)"RayTracer",
	(UBYTE *)"Auflösung",
	(UBYTE *)"Berechnen",
	(UBYTE *)"Extras"
};
UBYTE *Bef[MG]={
	(UBYTE *)"Laden",
	(UBYTE *)"Sichern",
	(UBYTE *)"Ende",
	(UBYTE *)"Low",
	(UBYTE *)"High",
	(UBYTE *)"Test",
	(UBYTE *)"Start",
	(UBYTE *)"Titel an",
	(UBYTE *)"Titel aus",
	(UBYTE *)"Count an",
	(UBYTE *)"Count aus",
	(UBYTE *)"Sichtbar",
	(UBYTE *)"Verdeckt",
	(UBYTE *)"W.ändern",
	(UBYTE *)"E.sichern"
};
UBYTE *wText[17]={
	(UBYTE *)"Bildschirmmitte X = ",
	(UBYTE *)"                Y = ",
	(UBYTE *)"                Z = ",
	(UBYTE *)"Blickrichtung   X = ",
	(UBYTE *)"                Y = ",
	(UBYTE *)"                Z = ",
	(UBYTE *)"Bildschirmabstand = ",
	(UBYTE *)"Brechungszahl     = ",
	(UBYTE *)"                   »",
	(UBYTE *)"Kugelnummer [RET] = ",
	(UBYTE *)"                   «",
	(UBYTE *)"Durchmesser       = ",
	(UBYTE *)"Kugelposition   X = ",
	(UBYTE *)"                Y = ",
	(UBYTE *)"                Z = ",
	(UBYTE *)"Sp/Gl/Li  (1/2/3) = ",
	(UBYTE *)"Kugel löschen (!)  ø"
};
UBYTE *bef []={			/* Text der Kommando-'Gadgets' */
	(UBYTE *)"DF0:",
	(UBYTE *)"DF1:",
	(UBYTE *)"CD /"
};
UBYTE *buf,*Ename[85];		/* Name eines Eintrags */
UBYTE werte[17][32];		/* Werte als Strings */
UBYTE filename[32]=NULL;	/* Filename im Gadget */
UBYTE undo[32];			/* UNDO Filename im Gadget */
UBYTE store[200];		/* Sicherheitskopie von aktuellDir */
UBYTE aktuellDir[200]={		/* enthält die aktuelle Dir */
	(UBYTE *)"SYS:"
};
STRPTR sprintf(),strcpy(),strcat(),index(),AllocMem();

struct Library			*OpenLibrary();
struct GfxBase			*GfxBase;
struct IntuitionBase 		*IntuitionBase;
struct MathTransBase 		*MathTransBase;
struct IntuiMessage 		*nachricht, *GetMsg();
struct RastPort 		*RP, *RP1, *RP2;
struct ViewPort 		*VP;
struct Window			*Window, *CWin, *DWin, *OpenWindow();
struct Screen 			*WBScreen, *Screen, *OpenScreen();
struct IntuiText		text[MG];
struct Lock	   	   	*dir, *Lock(), *CurrentDir();
struct FileInfoBlock 		*eintrag;
struct FileHandle 		*file, *Open();
struct BitMap			*map;
struct Menu 			menu[MA];
struct MenuItem  		item[MG];
struct StringInfo infoN={		/* Info fÜr Textgadget */
	filename,undo,0,31,0,0,0,0,0,0,0,0,NULL
};
struct Gadget		 Gad={		/* Textgadget */
	NULL,5,99,246,8,
	GADGHCOMP,RELVERIFY,STRGADGET,
	NULL,NULL,NULL,0,
	(APTR)&infoN,0,NULL
};
struct NewWindow 	DWindow={
	0,0,320,256,5,12,
	MOUSEBUTTONS|GADGETDOWN|GADGETUP,
	BORDERLESS|ACTIVATE|RMBTRAP|NOCAREREFRESH,
	&Gad,NULL,NULL,NULL,NULL,
	0,0,0,0,
	WBENCHSCREEN
};
struct NewWindow 	CWindow={
	0,0,30,20,14,15,
	0,WINDOWDRAG|NOCAREREFRESH,
	NULL,NULL,NULL,NULL,NULL,
	0,0,0,0,
	WBENCHSCREEN
};

/*
	Funktionen	
*/


VOID
setmenu()
{
	SHORT m[5];

	m[0] = 0;
	m[1] = M1;
	m[2] = M1+M2;
	m[3] = M1+M2+M3;
	m[4] = MG;

	for(i=MG-1;i>=0;i--){
		text[i].FrontPen=12;
		text[i].BackPen=15;
		text[i].DrawMode=JAM1;
		text[i].LeftEdge=0;
		text[i].TopEdge=1;
		text[i].ITextFont=NULL;
		text[i].IText=Bef[i];
		text[i].NextText=NULL;

		item[i].LeftEdge=0;
		item[i].Width=72;
		item[i].Height=10;
		item[i].Flags=ITEMTEXT|ITEMENABLED|HIGHCOMP;
		item[i].MutualExclude=NULL;
		item[i].ItemFill=(APTR)&text[i];
		item[i].Command=NULL;
		item[i].NextSelect=NULL;
	}
	for(j=1;j<=MA;j++){
		for(i=m[j]-1;i>=m[j-1];i--){
			if(i==m[j]-1) item[i].NextItem=NULL;
			else item[i].NextItem=&item[i+1];
			item[i].TopEdge=(i-(m[j-1]))*10;
		}
	}
	for(i=MA-1;i>=0;i--){
		if(i==MA-1) menu[i].NextMenu=NULL;
		else	    menu[i].NextMenu=&menu[i+1];
		menu[i].LeftEdge = i*80;
		menu[i].TopEdge  = 0;
		menu[i].Width    = 78;
		menu[i].Height   = 10;
		menu[i].Flags    = MENUENABLED;
		menu[i].MenuName = (BYTE *)Men[i];
		menu[i].FirstItem= &item[m[i]];
	}
	SetMenuStrip(Window,&menu[0]);
}

VOID
farben1()
{
	SetRGB4(VP, 0, 0,0,0);
	SetRGB4(VP, 1, 0,0,6);
	SetRGB4(VP, 2, 0,0,9);
	SetRGB4(VP, 3, 0,0,12);
	SetRGB4(VP, 4, 0,0,15);
	SetRGB4(VP, 5, 0,3,0);
	SetRGB4(VP, 6, 0,6,0);
	SetRGB4(VP, 7, 0,9,0);
	SetRGB4(VP, 8, 0,12,0);
	SetRGB4(VP, 9, 0,15,0);
	SetRGB4(VP, 10, 3,0,0);
	SetRGB4(VP, 11, 6,0,0);
	SetRGB4(VP, 12, 9,0,0);
	SetRGB4(VP, 13, 12,0,0);
	SetRGB4(VP, 14, 15,0,0);
	SetRGB4(VP, 15, 15,15,15);
}

VOID
farben2()
{
	a1=2;
	a2=5;
	a3=7;
	a4=7;	 /* ? */
	a5=8;

	SetRGB4(VP, 16, a1,a1,a1);
	SetRGB4(VP, 17, a2,a2,6);
	SetRGB4(VP, 18, a3,a3,9);
	SetRGB4(VP, 19, a4,a4,12);
	SetRGB4(VP, 20, a5,a5,15);
	SetRGB4(VP, 21, a1,3,a1);
	SetRGB4(VP, 22, a2,6,a2);
	SetRGB4(VP, 23, a3,9,a3);
	SetRGB4(VP, 24, a4,12,a4);
	SetRGB4(VP, 25, a5,15,a5);
	SetRGB4(VP, 26, 3,a1,a1);
	SetRGB4(VP, 27, 6,a2,a2);
	SetRGB4(VP, 28, 9,a3,a3);
	SetRGB4(VP, 29, 12,a4,a4);
	SetRGB4(VP, 30, 15,a5,a5);
	SetRGB4(VP, 31, 0,0,0);
}

VOID
closew()
{
	MoveScreen(WBScreen,0,-300*MUL);
	if(Window)		CloseWindow(Window);
	if(Screen)		CloseScreen(Screen);
	if(GfxBase)		CloseLibrary(GfxBase);
	if(IntuitionBase)	CloseLibrary(IntuitionBase);
	if(MathTransBase)	CloseLibrary(MathTransBase);

	exit(0);
}

VOID
screen(xw,yw,de,m)
	SHORT xw,yw,de,m;
{
	struct NewScreen NewScreen;
	SHORT modus;

	modus=((m==4)?HIRES|INTERLACE:0);
	NewScreen.LeftEdge=NewScreen.TopEdge=0;
	NewScreen.Width=xw;
	NewScreen.Height=yw;
	NewScreen.Depth=de;
	NewScreen.DetailPen=12;
	NewScreen.BlockPen=15;
	NewScreen.ViewModes=modus;
	NewScreen.Type=WBENCHSCREEN;
	NewScreen.DefaultTitle=(UBYTE *)"RayTracer";
	NewScreen.Font=NewScreen.Gadgets=NewScreen.CustomBitMap=NULL;

	if(!(Screen=(struct Screen *) OpenScreen(&NewScreen))) closew();
	VP  =&Screen->ViewPort;
}

VOID
window(xw,yw,br,ho)
	SHORT xw,yw,br,ho;
{
	struct NewWindow NewWindow;

	NewWindow.LeftEdge=xw;
	NewWindow.TopEdge=yw;
	NewWindow.Width=br;
	NewWindow.Height=ho;
	NewWindow.DetailPen=NewWindow.BlockPen=-1;
	NewWindow.IDCMPFlags=MOUSEBUTTONS|MENUPICK;
	NewWindow.Flags=SMART_REFRESH|ACTIVATE|BORDERLESS|BACKDROP;
	NewWindow.Type=WBENCHSCREEN;
	NewWindow.Title=NULL;
	NewWindow.Screen=NewWindow.BitMap=NULL;
	NewWindow.FirstGadget=NewWindow.CheckMark=NULL;
	NewWindow.MinWidth=NewWindow.MinHeight=0;
	NewWindow.MaxWidth=NewWindow.MaxHeight=0;

	if(!(Window=(struct Window *) OpenWindow(&NewWindow))) closew();
	RP=Window->RPort;
}

VOID
scrwin()
{
	px=BREITE;
	py=HOEHE;
	if(Window)	CloseWindow(Window);
	if(Screen)	CloseScreen(Screen);
	screen(px,py,6-MUL,((nf==1)?4:1));
	window(0,0,px,py);
	farben1();
	if(nf==2)	farben2();
	setmenu();
	ShowTitle(Screen,title);
}

VOID
aufbau()
{
	SHORT za= 0;
	bb    =.265;
	bh    =.19;
	if(!(file=Open("RTWerte",MODE_OLDFILE))){
		nk=3;
		nf=2;
		count=1;
		title=1;
		down=0;
		brz1=2.56;
		for(i=0;i<=nk;i++){
			for(j=0;j<=4;j++){
				ku[i][j]=data[za++];
			}
		}
		bm1=bm2=0;
		bm3=18;
		br1=5;
		br2=10;
		br3=-2.6;
		ba=.28;
	}
	else{
		Read(file,&nk,sizeof(SHORT));
		Read(file,&count,sizeof(SHORT));
		Read(file,&nf,sizeof(SHORT));
		Read(file,&title,sizeof(SHORT));
		Read(file,&down,sizeof(SHORT));
		Read(file,&bm1,sizeof(FLOAT));
		Read(file,&bm2,sizeof(FLOAT));
		Read(file,&bm3,sizeof(FLOAT));
		Read(file,&br1,sizeof(FLOAT));
		Read(file,&br2,sizeof(FLOAT));
		Read(file,&br3,sizeof(FLOAT));
		Read(file,&ba,sizeof(FLOAT));
		Read(file,&brz1,sizeof(FLOAT));
		for(i=0;i<=nk;i++){
			for(j=0;j<=4;j++) Read(file,&ku[i][j],sizeof(SHORT));
		}
		Close(file);
	}
}

VOID
openw()
{
	if(!(IntuitionBase=(struct  IntuitionBase *)
		OpenLibrary("intuition.library",0)))		closew();
	if(!(GfxBase=(struct GfxBase *)
		OpenLibrary("graphics.library",0)))		closew();
	if(!(MathTransBase=(struct MathTransBase *)
		OpenLibrary("mathtrans.library",0)))		closew();
	WBScreen=IntuitionBase->ActiveScreen;
	aufbau();
	MoveScreen(WBScreen,0,300*MUL);
	scrwin();
}

VOID
init()
{
	mbr1=br1;
	mbr2=br2;
	mbr3=br3;
	brz2=1/brz1;
	lq1=ku[0][1];
	lq2=ku[0][2];
	lq3=ku[0][3];
	farbe=0;
	xm=px*.5;
	ym=py*.5;
	bx1=br2;
	bx2=-br1;
	bx3=0;
	bx=sqrt(bx1*bx1+bx2*bx2+bx3*bx3);
	bx1=(bx1*bb)/(bx*px);
	bx2=(bx2*bb)/(bx*px);
	bx3=(bx3*bb)/(bx*px);
	by1=-br1*br3;
	by2=-br2*br3;
	by3= br2*br2+br1*br1;
	by=sqrt(by1*by1+by2*by2+by3*by3);
	by1=(by1*bh)/(by*py);
	by2=(by2*bh)/(by*py);
	by3=(by3*bh)/(by*py);
	br=sqrt(br1*br1+br2*br2+br3*br3);
	br1=br1*ba/br;
	br2=br2*ba/br;
	br3=br3*ba/br;
	ca[1]=bm1-br1;
	ca[2]=bm2-br2;
	ca[3]=bm3-br3;
}

VOID
wtoa()
{
	if((br1==0) && (br2==0))	br1=br2	=.000001;
	if(ba==0)			ba	=.000001;
	if(ku[kza][4]>2)		ku[kza][4]=2;
	ku[0][4]=3;
	sprintf(werte[0], "%f",bm1);
	sprintf(werte[1], "%f",bm2);
	sprintf(werte[2], "%f",bm3);
	sprintf(werte[3], "%f",br1);
	sprintf(werte[4], "%f",br2);
	sprintf(werte[5], "%f",br3);
	sprintf(werte[6], "%f",ba);
	sprintf(werte[7], "%f",brz1);
	sprintf(werte[9], "%d",kza);
	for(i=0;i<=4;i++) sprintf(werte[i+11], "%d",ku[kza][i]);
}

VOID
atow()
{
	bm1 =(FLOAT)(atof(werte[0]));
	bm2 =(FLOAT)(atof(werte[1]));
	bm3 =(FLOAT)(atof(werte[2]));
	br1 =(FLOAT)(atof(werte[3]));
	br2 =(FLOAT)(atof(werte[4]));
	br3 =(FLOAT)(atof(werte[5]));
	ba  =(FLOAT)(atof(werte[6]));
	brz1=(FLOAT)(atof(werte[7]));
	kza =(SHORT)(atoi(werte[9]));
	for(i=0;i<=4;i++)		ku[kza][i]=(SHORT)(atoi(werte[i+11]));
	if((br1==0) && (br2==0))	br1=br2	=.000001;
	if(ba==0)			ba	=.000001;
	if(ku[kza][4]>2)		ku[kza][4]=2;
	ku[0][4]=3;
}

VOID
ESave()
{
	if(!(file=Open("RTWerte",MODE_NEWFILE))){
		DisplayBeep(0);
		return;
	}
	Write(file,&nk,sizeof(SHORT));
	Write(file,&count,sizeof(SHORT));
	Write(file,&nf,sizeof(SHORT));
	Write(file,&title,sizeof(SHORT));
	Write(file,&down,sizeof(SHORT));
	Write(file,&bm1,sizeof(FLOAT));
	Write(file,&bm2,sizeof(FLOAT));
	Write(file,&bm3,sizeof(FLOAT));
	Write(file,&br1,sizeof(FLOAT));
	Write(file,&br2,sizeof(FLOAT));
	Write(file,&br3,sizeof(FLOAT));
	Write(file,&ba,sizeof(FLOAT));
	Write(file,&brz1,sizeof(FLOAT));
	for(i=0;i<=nk;i++){
		for(j=0;j<=4;j++) Write(file,&ku[i][j],sizeof(SHORT));
	}
	Close(file);
}

VOID
kugschnitt()
{
	ke1=ca1-ku[nr][1];
	ke2=ca2-ku[nr][2];
	ke3=ca3-ku[nr][3];
	kf1=2*(cr1*cr1+cr2*cr2+cr3*cr3);
	kf2=2*(cr1*ke1+cr2*ke2+cr3*ke3);
	kf3=ke1*ke1+ke2*ke2+ke3*ke3-ku[nr][0]*ku[nr][0];
	kf4=kf2*kf2-2*kf1*kf3;
	if(kf4<0){
		k=0;
		return;
	}
	k1=(-kf2+sqrt(kf4))/kf1;
	k2=(-kf2-sqrt(kf4))/kf1;
	k=k1;
	if(k1>k2)	k=k2;
}

VOID
kugspiegel()
{
	r1=ca1+k*cr1-ku[nr][1];
	r2=ca2+k*cr2-ku[nr][2];
	r3=ca3+k*cr3-ku[nr][3];
	h=(cr1*r1+cr2*r2+cr3*r3)/(r1*r1+r2*r2+r3*r3);
	cr1=cr1-2*h*r1;
	cr2=cr2-2*h*r2;
	cr3=cr3-2*h*r3;
	ca1=r1+ku[nr][1];
	ca2=r2+ku[nr][2];
	ca3=r3+ku[nr][3];
	ff++;
}


VOID
brechung()
{
	r1=ku[nr][1]-ca1-k*cr1;
	r2=ku[nr][2]-ca2-k*cr2;
	r3=ku[nr][3]-ca3-k*cr3;
	gf1=cr1*r1+cr2*r2+cr3*r3;
	gf2=cr1*cr1+cr2*cr2+cr3*cr3;
	gf3=r1*r1+r2*r2+r3*r3;
	gf4=(gf1*gf1)/(gf2*gf3);
	gf5=(1-gf4)/brz;
	si=sqrt(fabs(gf5));
	co=sqrt(fabs(1-gf5));
	gh1=r2*cr3-r3*cr2;
	gh2=r3*cr1-r1*cr3;
	gh3=r1*cr2-r2*cr1;
	g1=gh2*r3-gh3*r2;
	g2=gh3*r1-gh1*r3;
	g3=gh1*r2-gh2*r1;
	gr=co/sqrt(fabs(gf3));
	gg=si/sqrt(fabs(g1*g1+g2*g2+g3*g3));
	cr1=r1*gr+g1*gg;
	cr2=r2*gr+g2*gg;
	cr3=r3*gr+g3*gg;
}

VOID
kugglas()
{
	kk=1;
	r1=ca1+k*cr1-ku[nr][1];
	r2=ca2+k*cr2-ku[nr][2];
	r3=ca3+k*cr3-ku[nr][3];
	h=(cr1*r1+cr2*r2+cr3*r3)/(r1*r1+r2*r2+r3*r3);
	crh1=cr1-2*h*r1;
	crh2=cr2-2*h*r2;
	crh3=cr3-2*h*r3;
	cah1=r1+ku[nr][1];
	cah2=r2+ku[nr][2];
	cah3=r3+ku[nr][3];
	ke1=cah1-ku[0][1];
	ke2=cah2-ku[0][2];
	ke3=cah3-ku[0][3];
	kf1=2*(crh1*crh1+crh2*crh2+crh3*crh3);
	kf2=2*(crh1*ke1+crh2*ke2+crh3*ke3);
	kf3=ke1*ke1+ke2*ke2+ke3*ke3-ku[0][0]*ku[0][0];
	kf4=kf2*kf2-2*kf1*kf3;
	if(kf4<0)	kk=0;
	if(kk==1){
		farbe=15;
		return;
	}
	brz=brz1;
	brechung();
	kf1=2*(cr1*cr1+cr2*cr2+cr3*cr3);
	kf2=2*(cr1*r1+cr2*r2+cr3*r3);
	kf3=gf3-ku[nr][0]*ku[nr][0];
	kf4=kf2*kf2-2*kf1*kf3;
	if(kf4<0)	k=0;
	else{
		k1=(-kf2+sqrt(kf4))/kf1;
		k2=(-kf2-sqrt(kf4))/kf1;
		k=k1;
		if(k1<k2)	k=k2;	
	}
	brz=brz2;
	brechung();
	ca1=ku[nr][1]-r1;
	ca2=ku[nr][2]-r2;
	ca3=ku[nr][3]-r3;
	if(nf==2)	fm=16;
	else		ff+=2;
}

VOID
schatten()
{
	fh=0;
	ca1=s1;
	ca2=s2;
	ca3=0;
	cr1=lq1-s1;
	cr2=lq2-s2;
	cr3=lq3;
	for(j=1;j<=nk;j++){
		nr=j;
		kugschnitt();
		if(k>0){
			if(ku[nr][4]==1){
				ff+=2;
				return;
			}
			fh++;
		}
	}
	if(fh>2)	fh=2;
	ff+=fh;
}

VOID
bodschnitt()
{
	if(cr3>=0){
		if(ff>3){
			farbe=fm;
		}
		else{
			farbe=4-ff+fm;
			return;
		}
	}
	bodk=ca3/cr3;
	s1=ca1-bodk*cr1;
	s2=ca2-bodk*cr2;
	schatten();
	if(ff>4){
		farbe=fm;
		return;
	}
	if(((SHORT)(s1*.05)*2-(SHORT)(s1*.1))==
					((SHORT)(s2*.05)*2-(SHORT)(s2*.1))){
		farbe=9-ff+fm;
	}
	else{
		farbe=14-ff+fm;
	}
}

VOID
raytrace()
{
	nsh=-1;
	kh=0.0;
	for(i=0;i<=nk;i++){
		if(i!=ns){
			nr=i;
			kugschnitt();
			if(k){
				if((kh==0.0) || (k<kh)){
					nsh=i;
					kh=k;
				}
			}
		}
	}
	if(kh<=0){
		bodschnitt();
		return;
	}
	if(nsh==0){
		farbe=15;
		return;
	}
	ns=nsh;
	k=kh;
	nr=ns;
	if(ku[ns][4]==1) kugspiegel();
	if(ku[ns][4]==2) kugglas();
	if(farbe==15)	 return;
	raytrace();
}

ULONG
message(win)
	struct Window *win;
{
	ULONG cl=0;
	code=0;

	if(nachricht=GetMsg(win->UserPort)){
		cl  =nachricht->Class;
		code=nachricht->Code;
		ReplyMsg(nachricht);
	}
	return(cl);
}

VOID
block(rport,col,x1,y1,x2,y2)
/* Block zeichnen (beliebige Farbe, beliebige Position, beliebige Größe */
	struct RastPort	*rport;
	SHORT col,x1,x2,y1,y2;
{
	SetAPen(rport, col);                /* Farbe        */
	SetDrMd(rport, JAM1);               /* Zeichenmodus */
	RectFill(rport, x1,y1,x2,y2);       /* Rechteck     */
}

VOID
rev(lnr)
/* der gewählte Fileeintrag wird gekennzeichnet */
	SHORT lnr;
{
	SetDrMd(RP2, COMPLEMENT);          /* Zeichenmodus */
	RectFill(RP2, 5,lnr+2,245,lnr+9); /* Rechteck     */
}

SHORT
cd(newdir)
/* festlegen einer neuen aktuellen Directory */
	UBYTE *newdir;
{
	SHORT bad=0;

	NR=0;
	strcpy(store,aktuellDir); /* 'Sicherheitskopie' */
	if(strlen(newdir)==0) return(0);
	eintrag = (struct FileInfoBlock *) 
				AllocMem(sizeof(struct FileInfoBlock),0);	
	if (*newdir == '/') {	  /* aufsteigen */
		for (i=strlen(aktuellDir);aktuellDir[i]!='/' && 
						aktuellDir[i]!=':';i--);
		if(aktuellDir[i] == ':') i++;
		aktuellDir[i] = '\0';
	}
	else if (newdir[strlen(newdir)-1] != ':'){ /* kein Rootdirectory ? */
		if(aktuellDir[strlen(aktuellDir)-1] != ':') 
						strcat(aktuellDir,"/");
		strcat(aktuellDir, newdir); /* neues Verzeichnis anhängen */
	     }	   			
	     else strcpy(aktuellDir, newdir); /* Rootdirectory */
	     if((dir = Lock(aktuellDir, ACCESS_READ)) != 0){
			if(Examine(dir,eintrag)!=0){
				if(eintrag->fib_DirEntryType<=0) bad++;
				else dir=CurrentDir(dir);
			}
			else bad++;
	     }
	     else bad++;
	     if (bad) {	/* Das neue Verzeichnis existiert nicht ! */
		strcpy(aktuellDir,store);/* RÜckkopieren der Sicherheitskopie */
		bad=1;
	     }
	UnLock(dir);
	FreeMem(eintrag,sizeof(struct FileInfoBlock));
	return(bad);	/* OK */
}


STRPTR
strmem(von)
/* Platz schaffen für den eben gelesenen Namen */
	STRPTR von;
{
	STRPTR nach;

	if((nach = AllocMem(strlen(von)+1,MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
		 strcpy(nach,von);
	return(nach);
}

SHORT
readDir()
{
	zaehler = 0;	/* zählt die Einträge */
	eintrag = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),0);
	dir = Lock(aktuellDir,ACCESS_READ);
	if((dir == NULL) | !Examine(dir,eintrag)){
		FreeMem(eintrag,sizeof(struct FileInfoBlock));
		return(1);/* nicht gefunden */
	}
	if (first == 0){	/* Root-Directory lesen */
		first++;
		if(!index(eintrag->fib_FileName,' ')){
			strcpy(aktuellDir,eintrag->fib_FileName);
			strcat(aktuellDir,":"); 
		}
	} 
	ExNext(dir,eintrag); 
	while (IoErr() != ERROR_NO_MORE_ENTRIES){ /* Dir-Einträge lesen */
		if(zaehler+1>80) continue;
		if (eintrag->fib_DirEntryType > 0){  /* Directoryname */
			zaehler++;
			Ename[zaehler]=strmem(eintrag->fib_FileName);
			zfarbe[zaehler]=3;
		}
		else{		/* Filename */
			zaehler++;
			Ename[zaehler]=strmem(eintrag->fib_FileName);
			if(Ename[zaehler][strlen(Ename[zaehler])-2]!='-')
								      zaehler--;
			else zfarbe[zaehler]=4;
		}
		ExNext(dir,eintrag); /* nächster Eintrag */
	}
        for(i=zaehler+1;i<85;i++){   /* auffÜllen mit Nullbytes */
		strcpy(Ename[i],"");
		zfarbe[i]=0;
        }
	FreeMem(eintrag,sizeof(struct FileInfoBlock));
        return(0);	/* OK */
}


VOID
print(rport,text,col,xp,yp)
	struct RastPort	*rport;
	STRPTR text;
	SHORT col,xp,yp;
{
	SetAPen(rport, col);
	SetDrMd(rport, JAM1);
	Move(rport, xp, yp);
	Text(rport,text,strlen(text));
}

VOID
Wdir()
/* Directoryeinträge in großen Block schreiben */
{
	block(RP2,0,5,5,245,91);          /* großer  Block  */
	block(RP2,0,247,5,265,91);         /* SchieberfÜhrung */
	block(RP2,13,249,NR+6,263,NR+9);    /* Schieber (Knopf) */
	if(zaehler==0){        /* kein Eintrag (bei Fehler) */
		strcpy(filename,"");
		RefreshGadgets(&Gad,DWin,NULL);
		return;
	}
	for(i=1;i<=10;i++) /* neu schreiben */
		print(RP2,Ename[NR+i],zfarbe[NR+i],5,(i+1)*8);
}


VOID
fehler()
/* Ein Verzeichnis wurde nicht gefunden */
{
	block(RP2,15,250,100,315,125);
	print(RP2,"READ",12,269,110);
	print(RP2,"READ",14,270,111);
	print(RP2,"ERROR",12,264,120);
	print(RP2,"ERROR",14,265,121);
	WKLICK;
	WKLICK;
	block(RP2,3,250,100,315,125);
	print(RP2,"A",1,286,110);
	print(RP2,"G",1,291,115);
}

VOID
Ndir(new)
	STRPTR new;
{
	if(cd(new)) fehler(); /* neue Directory */
	if(readDir()){        /* Directory lesen */
		fehler();
		zaehler=0;
	}
	Wdir();               /* Directory schreiben */
}

VOID
setgad()
{
	NR=0;
	block(RP2,1,0,147,319,165);
	block(RP2,2,1,148,318,164);
	print(RP2,"  -*- Ray Tracer -*-",15,78,159);
	print(RP2,"    ·  DiskmenÜ  ·",2,78,180);
	print(RP2,"       DiskmenÜ",4,77,181);

	block(RP2,3,0,0,320,130); /* Block im Fenster */

	block(RP2,2,4,4,266,92);
	block(RP2,0,5,5,245,91); /* großer Block */
	Wdir();	              /* Schieber     */

	block(RP2,0,4,96,246,109);	
	block(RP2,15,5,97,245,108); /* Textgadget */

	for(i=0;i<2;i++){
		block(RP2,2,i*165+4,114,i*165+81,126);
		block(RP2,15,i*165+5,115,i*165+80,125); /* ok & stop */
	}
	print(RP2,"OK",12,34,123);
	print(RP2,"STOP",12,193,123);
	print(RP2,"A",1,286,110);
	print(RP2,"G",1,291,115);

	for(i=0;i<3;i++){
		block(RP2,2,270,i*33+4,312,i*33+26);
		block(RP2,15,271,i*33+5,311,i*33+25); /* 'df0:', 'df1:', 'cd /' */
		print(RP2,bef[i],12,275,i*33+17);
	}
	RefreshGadgets(&Gad,DWin,NULL);
}


SHORT
checkgad()
/* Auswertung bei Mausklick */
{
	register i,x,y,knopfy;

	x=DWin->MouseX;
	y=DWin->MouseY; /* Position des Mauszeigers beim KLICK */
	if(x>270 && x<311){
		for(i=0;i<3;i++){ /* 'df0:', 'df1:', 'cd /' */
			if(y>i*33+5 && y<i*33+25) return(i+1);
		}
	}
	if(y>115 && y<125){
		if(x> 4 && x< 86) return(4); /*  OK  */
		if(x>164 && x<246) return(5); /* STOP */
	}
	if(x>245 && x<265 && y>5 && y<91){               /* SchieberfÜhrung */
		if(y<NR+6 && NR>0) return(6);                /* Über  Knopf */
		if(y>NR+9 && NR<zaehler-10) return(7);       /* unter Knopf */
		if(y>=NR+6 && y<=NR+9){ 		 /* genau auf Knopf */
			WKLICK{
				knopfy=y;
				while((y=DWin->MouseY)==knopfy){
				    if((class=message(DWin))==MOUSEBUTTONS)
					 return(0);
				}
				NR+=(y-knopfy);
				if(NR<0 || NR>zaehler-10){ /* zu hoch/tief */
				     NR-=(y-knopfy);
				     WKLICK;
				     return(0);
				}
				Wdir(); /* Directory neu schreiben */
			}
		}
		return(0);
	}
	if(x>5 && x<245 && y>8 && y<88){ /* Klick im großen Block */
		fnr=NR+(y-2)/8;           /* Filenummer ermitteln  */
		return(8);
	}
	return(0);
}

VOID
disk()
{
	register i, gnr, wert, ende=0;

	DWindow.Width =BREITE;
	DWindow.Height=HOEHE;
	infoN.Buffer  =filename;
	Gad.LeftEdge=  5;
	Gad.TopEdge = 99;
	Gad.Width   =246;
	Gad.Height  =  8;
	if(!(DWin=(struct Window *)OpenWindow(&DWindow)))	return;
	RP2=DWin->RPort;
	SetRGB4(VP, 0, 13,13,13);
	setgad();          /* Arbeitsfeld erstellen    */
	WindowToFront(DWin);
	while(ende==0){
		switch(class=message(DWin)){
			case GADGETDOWN:  /* Textgadget Übernimmt Intuition */
			case  GADGETUP :{
				break;
			}
			case MOUSEBUTTONS:{ /* Mausklick - mein Job */
				gnr=checkgad(); /* 'Gadget' ermitteln */
				switch(gnr){
					case 1:{ /* DF0: 'Gadget' */
					   first=0;
					   Ndir("DF0:");
					   strcpy(filename,"");
					   RefreshGadgets(&Gad,DWin,NULL);
					   WKLICK;
					   break;
					}
					case 2:{ /* DF1: 'Gadget' */
					   first=0;
					   strcpy(filename,"");
					   RefreshGadgets(&Gad,DWin,NULL);
					   Ndir("DF1:");
					   WKLICK;
					   break;
					}
					case 3:{ /* CD / 'Gadget' */
					   strcpy(filename,"");
					   RefreshGadgets(&Gad,DWin,NULL);
					   Ndir("/");
					   WKLICK;
					   break;
					}
					case 4:{ /* OK 'Gadget' */
					   WKLICK;
					   wert=1;
					   ende++;
					   break;
					}
					case 5:{ /* STOP 'Gadget' */
					   WKLICK;
					   strcpy(filename,"");
					   wert=0;
					   ende++;
					   break;
					}
					case 6:{ /* Über Kopf */
					   NR--;
					   Wdir();
					   WKLICK;
					   break;
					}
					case 7:{ /* unter Knopf */
					   NR++;
					   Wdir();
					   WKLICK;
					   break;
					}
					case 8:{ /* Filename */
					   rev((fnr-NR)*8);
					   if(zfarbe[fnr]==4){ 

						strcpy(filename,Ename[fnr]);
						RefreshGadgets(&Gad,DWin,NULL);
						WKLICK;
						rev((fnr-NR)*8);
						break;
					   }
					   WKLICK;
					   strcpy(filename,"");
					   RefreshGadgets(&Gad,DWin,NULL);
					   rev((fnr-NR)*8);
					   Ndir(Ename[fnr]);
					   break;
					}
					default: break;
				} /* switch gnr */
				break;
			} /* case MOUSEBUTTONS */
			default:{
				 break;
			}
		} /* switch class */
	} /* while */
	SetRGB4(VP, 0, 0,0,0);
	CloseWindow(DWin);
	DisplayBeep(0);
}

VOID
savebild()
{
	disk();
	if(strlen(filename)==0) return;
	if(filename[strlen(filename)-2]!='-') 	strcat(filename,nn[nf-1]);
	if(!(file=Open(filename,MODE_NEWFILE))){
		DisplayBeep(0);
		return;
	}
	map=RP->BitMap;
	ShowTitle(Screen,0);
	for(i=0;i<6-MUL;i++){
		buf=map->Planes[i];
		Write(file,buf,BREITE*HOEHE/8);
	}
	Close(file);
	ShowTitle(Screen,title);
}

VOID
loadbild()
{
	disk();
	if(strlen(filename)==0) return;

	if(!(file=Open(filename,MODE_OLDFILE))){
		DisplayBeep(0);
		return;
	}
	if(filename[strlen(filename)-1]=='h') nf=1;
	else nf=2;
	scrwin();
	ShowTitle(Screen,0);
	map=RP->BitMap;
	for(i=0;i<6-MUL;i++){
		buf=map->Planes[i];
		Read(file,buf,BREITE*HOEHE/8);
	}
	Close(file);
	ShowTitle(Screen,title);
}

VOID
start()
{
	BYTE text[3];

	SetRGB4(VP, 1, 0,0,6);
	SetRGB4(VP, 2, 0,0,9);
	block(RP,0,0,0,BREITE,HOEHE);
	if(count){
		CWindow.LeftEdge=BREITE-30;
		if(!(CWin=(struct Window *) OpenWindow(&CWindow))){
			DisplayBeep(0);
			return;
		}
		RP1=CWin->RPort;
	}
	if(down)	MoveScreen(Screen,0,300*MUL);
	for(y=ya;y>=-ym;y--){
		if((class=message(Window))==MOUSEBUTTONS){
			while((class=message(Window))!=MOUSEBUTTONS);
			if(count)	CloseWindow(CWin);
			if(down)	MoveScreen(Screen,0,-300*MUL);
			DisplayBeep(0);
			return;
		}
		if(count){
			sprintf(text,"%d",y+ym);
			block(RP1,15,0,10,30,20);
			SetAPen(RP1, 13);
			Move(RP1, 4, 18);
			Text(RP1,text,strlen(text));
		}
		h1=br1+by1*y;
		h2=br2+by2*y;
		h3=br3+by3*y;
		for(x=-xm;x<=xm;x++){
			farbe=0;
			ff=0;
			fm=0;
			ns=0;
			ca1=ca[1];
			ca2=ca[2];
			ca3=ca[3];
			cr1=bx1*x+h1;
			cr2=bx2*x+h2;
			cr3=h3;
			raytrace();
			SetAPen(RP,farbe);
			WritePixel(RP,x+xm,ym-y);
		}
	}
	if(count)	CloseWindow(CWin);
	if(down)	MoveScreen(Screen,0,-300*MUL);
	DisplayBeep(0);
}

VOID
setW()
/* Werte darstellen */
{
	/* Damit's schneller geht - RectFill, Move und Text */
	SetDrMd(RP2, JAM1);
	SetAPen(RP2, 0);
	RectFill(RP2,BREITE/20+160,HOEHE/32*4-8,BREITE,60+(HOEHE/32)*19);
	SetAPen(RP2, 7);
	for(i=0;i<17;i++){
		message(DWin);
		Move(RP2,BREITE/20+160,i*4+(HOEHE/32)*(i+4));
		Text(RP2,werte[i],strlen(werte[i]));
	}
}

VOID
getW()
{
	SHORT zeile,posx,posy,ende=1;

	DWindow.Width =BREITE;	/* Fenstergröße festlegen */
	DWindow.Height=HOEHE;
	if(!(DWin=(struct Window *) OpenWindow(&DWindow))){
		DisplayBeep(0);
		return;
	}
	RP2=DWin->RPort;
	SetRGB4(VP, 0, 13,13,13);	/* Hintergrundfarbe festlegen */
	wtoa();		/* Werte in Strings wandeln ... */
	block(RP2,0,0,0,BREITE,HOEHE);
	block(RP2,6,0,0,BREITE,15);
	block(RP2,13,10,1,BREITE-10,14);
	print(RP2,"-*- Ray Tracer -*-",6,BREITE/2-72,10);
	print(RP2,"-*- Ray Tracer -*-",0,BREITE/2-71,11);
	block(RP2,6,BREITE/4,HOEHE-MUL*20,3*BREITE/4,HOEHE-2);
	block(RP2,13,BREITE/4+10,HOEHE-MUL*20+1,3*BREITE/4-10,HOEHE-3);
	print(RP2,"OK",15,BREITE/2-8,HOEHE-MUL*10+2);
	for(i=0;i<17;i++){
	    print(RP2,wText[i],6,BREITE/20,i*4+(HOEHE/32)*(i+4));
	    print(RP2,werte[i],7,BREITE/20+160,i*4+(HOEHE/32)*(i+4));
	}
	while(ende){
		WKLICK;	/* Taste drÜcken ... */
		WKLICK; /* und loslassen */
		posx=DWin->MouseX; 	  /* Position des Zeigers festhalten */
		posy=DWin->MouseY;
		if(ende==10){ 	  /* ein Gadget wurde bereits einmal gewählt */
			ende=1;
			atow();		    /* Strings in Floatwerte wandeln */
			if(zeile==9){			 /* neue Kugelanzahl */
				if(kza>99) kza=99;     /* Kugelzähler max 99 */
				if(kza>nk){    /* neue Kugeln initialisieren */
					nk=kza;
					for(i=0;i<=4;i++) ku[kza][i]=0;
				}
			}
			wtoa(); 		 /* Werte in Strings wandeln */
			while(class=message(DWin));	      /* WICHTIG !!! */
			setW(); 		       /* ... und darstellen */
			while(class=message(DWin));	      /* WICHTIG !!! */
		}
		if((posy>=4+HOEHE/32)&&(posy<=64+(HOEHE/32)*20)&&
						(posx>=BREITE/20+150)){
					      /* Klick im erlaubten Bereich */
			for(i=0;i<17;i++){
				if((posy>=i*4+(HOEHE/32)*(i+4)-8)&&
					(posy<=i*4+(HOEHE/32)*(i+4))){
					zeile=i;
					ende=10;
				}
			}			       /* Zeile feststellen */
			switch(zeile){
				case 8:{		     /* Zeile 8 = » */
				 	kza++;
					if(kza>nk) kza=0;
					wtoa();
					setW();
					ende=1;
					break;
				}
				case 10:{		   /* Zeile 10 = « */
					kza--;
					if(kza<0) kza=nk;
					wtoa();
					setW();
					ende=1;
					break;
				}
				case 16:{		  /* Kugel löschen */
					if(nk>0){
						for(i=kza;i<=nk;i++){
							for(j=0;j<=4;j++){
							    ku[i][j]=ku[i+1][j];
							}      /* kopieren */
					    	}	      /* aufrücken */
						nk--;
						if(kza>nk) kza=nk;
						wtoa();
						setW();
						ende=1;
					}
					break;
				}
				default:{	   /* Gadget positionieren */
				    infoN.Buffer=werte[zeile];
				    Gad.LeftEdge=BREITE/20+160;
				    Gad.TopEdge =zeile*4+(HOEHE/32)*(zeile+4)-6;
				    RefreshGadgets(&Gad,DWin,NULL);
				}
			}/* switch zeile */
		}/* if im Bereich ? */
		else	if((posy>HOEHE-MUL*20)&&
				(posx>BREITE/4)&&(posx<3*BREITE/4)){
				atow();	       /*Strings in Werte wandeln */
				block(RP2,0,0,0,BREITE,HOEHE);
				for(ende=13;ende>0;ende--){
					Delay(2);
					SetRGB4(VP, 0, ende,ende,ende);
				}			   /* ausblenden */
			}
	}/* while */
	CloseWindow(DWin);
}/* getW() */


VOID
main()
{
      USHORT ce;
      ULONG cs;

      openw();
      while(1){
	   cs=message(Window);
	   ce=code;
	   switch(cs){
		case MENUPICK:{	/* Auswahl aus MenÜ */
		    if(ce == MENUNULL) break;
		    switch (MENUNUM(ce)){
			case 0:{	 /* Ray Tracer */
				switch(ITEMNUM(ce)){
					case 0:{	/* Laden */
						loadbild();
						break;
					}
					case 1:{	/* Sichern */
						savebild();
						break;
					}
					case 2:{	/* Quit */
						closew();
						break;
					}
					default:{
						break;
					}
				}
				break;
			}
			case 1:{	 /* Auflösung */
				switch(ITEMNUM(ce)){
					case 0:{	/* Low */
						nf=2;
						scrwin();
						break;
					}
					case 1:{	/* High */
						nf=1;
						scrwin();
						break;
					}
					default:{
						break;
					}
				}
				break;
			}
			case 2:{ 	/* Berechnung */
				switch(ITEMNUM(ce)){
					case 0:{	/* Test */
						px=62*MUL;
						py=50*MUL;
						init();
						ya=ym;
						start();
						br1=mbr1;
						br2=mbr2;
						br3=mbr3;
						break;
					}
					case 1:{	/* Start */
						px=BREITE;
						py=HOEHE;
						init();
						ya=ym;
						start();
						br1=mbr1;
						br2=mbr2;
						br3=mbr3;
						break;
					}
					default:{
						break;
					}
				}
				break;
			}
			case 3:{ 	/* Extras */
				switch(ITEMNUM(ce)){
					case 0:{	/* Titel an */
						title=1;
						ShowTitle(Screen,1);
						break;
					}
					case 1:{	/* Titel aus */
						title=0;
						ShowTitle(Screen,0);
						break;
					}
					case 2:{	/* Count an */
						count=1;
						break;
					}
					case 3:{	/* Count aus */
						count=0;
						break;
					}	
					case 4:{	/* sichtbar */
						down=0;
						break;
					}
					case 5:{	/* verdeckt */
						down=1;
						break;
					}
					case 6:{	/* Werte ändern */
						getW();	
						break;
					}
					case 7:{	/* Extras sichern */
						ESave();
						break;
					}
					default:{
						break;
					}
				}/* switch Items */
				break;
			}/* case Extras */
			default:{	/* MenÜstreifen */
				break;
			}
		    }/* switch Menü */
		    break;
		}
		default:{	/* message */
			break;
		}
	   }/* switch cs */
      }/* while 1 */
}/* main() */
