#include "AllTools.h"
#include "fractal.h"

#define NIL_POINTER       0L
#define REMOVE_ALL_EVENTS 0

#define	mrBlob1	((x >> 8) & 255) + (y & 65280)
#define	mrBlob2	((x >> 8) & 254) + (y & 65024)
#define	mrBlob3	((x >> 8) & 252) + (y & 64512)
#define heightShift 7

void 	Maketables(void);
void 	ToolBoxInit(void);
void 	WindowInit(void);
void	MemInit(void);
void	MemEnd(void);
void 	FillWindowsBlack( void );
void	WindowMove(void);

#if GENERATING68K
	asm		copyOffScreen(void);
	asm 	clearOffScreen(void);
#else
	void	copyOffScreen(void);
	void 	clearOffScreen(void);
#endif

void 	ToDrawX1(void);
void 	ToDrawX2(void);
void 	ToDrawX4(void);

void 	DoPreferences(void);
void	DoOther(void);
void	MakeMap(void);
void 	ChangeHeight( int pss, int height );
void	Smooth(int pss);
void 	MakeCols(void);
void 	BlurMap(void);
void	Quit(void);
int		hght(short x, short y);
int 	hght2(short x, short y);
void	fixVars(void);

typedef struct
	{
		unsigned char	map[256][256];
	}  MAP, *mapPeek;

typedef struct
	{
		unsigned long	colorGrid[256][512];
	} aCol,	*aColPeek;

WindowPtr 			BackWindow, theGameWindow;
PaletteHandle		fracCols;
Ptr					offScreen;
Ptr theTemp, theTemp2, theTemp3;
videoInfo	theScreen;
Ptr ScrnBase;

long	hhhh, xxxx, yyyy, cxxxx, cyyyy;
long	mapX, mapY, mapXp, mapYp;
long	windX, windY, rayLen, xStep, yStep, windX2, windY2, windX4, windXstep, windYsteps, yOffSet;
long	cs[2560], sn[2560], angle;
long	theSize;
long	rBts, xres2, yres2, orfset;
long	randSeed, waterLevel;

long	velocity;
short	pNum;
mapPeek	the, the2;
aColPeek the3;
short	oldBitDepth;
long	tempHeight;

short	RayLengthOption, PixelSizeOption, LandScapeOption, WindowSizeOption;

long	mx2, my2, scale;

long	keyBoard, maxHeight, roughness;

void main( void )
{
Point	tmpMouse;
KeyMap	theKeys;
Boolean anEvent, intEnd;
EventRecord	theEvent;

MbarInit();

RayLengthOption = 6;
PixelSizeOption = 4;
LandScapeOption = 6;
WindowSizeOption = 4;
maxHeight = 2;
roughness = 2;
keyBoard = control_is_mouse;

pNum	=	8;

windX 	= 	256;
windY 	= 	192;
rayLen	=	511;
xStep	=	4;
yStep	=	2;

waterLevel=	0;

mapX	=	256;
mapY	=	256;
mapXp	=	mapX - 1;
mapYp	=	mapY - 1;

	ToolBoxInit();

	qd.randSeed = (unsigned long)TickCount();
	randSeed = Random() + 32767;
	if (randSeed == 0) randSeed = 1;

	HideMenuBar();
	WindowInit();
	MemInit();
	Maketables();

fixVars();

// Scale is used to stadardise movement using the mouse on larger screens.
scale = (long)(theScreen.resolutionX);

	while(TRUE)
	{
		DoPreferences();
		
		fixVars();	
		WindowMove();

		MakeMap();
		BlurMap();
		MakeCols();

		if ( keyBoard == control_is_keys ) { mx2 = xres2; my2 = yres2; }

		clearOffScreen();
hhhh = ((long)(the->map[(short)((yyyy >> 8) & 255)][(short)((xxxx >> 8) & 255)] + 4) << heightShift);

intEnd = FALSE;

			while( intEnd == FALSE )
			{
			anEvent = GetNextEvent( 0xffff, &theEvent );
			GetKeys( theKeys );

				if ( keyBoard == control_is_mouse )
						{
							// Get and standardise the mouse position.
							GetMouse( &tmpMouse);
							mx2 = ((long)tmpMouse.h * scale) >> 9;
							my2 = ((long)tmpMouse.v * scale) >> 9;
						}

				if ( keyBoard == control_is_keys )
						{
							if ( ((theKeys[3] >> 3) & 0x01) == TRUE )	mx2 -= 32;
							if ( ((theKeys[3] >> 4) & 0x01) == TRUE )	mx2 += 32;
							if ( ((theKeys[3] >> 6) & 0x01) == TRUE )	my2 -= 32;
							if ( ((theKeys[3] >> 5) & 0x01) == TRUE )	my2 += 32;
							
							if ( mx2 > 512 ) mx2 = 512;
							if ( mx2 <   0 ) mx2 =   0;
							if ( my2 > 440 ) my2 = 440;
							if ( my2 <   0 ) my2 =   0;
						}

	// This part checks if you have pushed enter/space or the mouse button thus ending current flight
	if ( (theKeys[1] >>  9) & 0x01 == TRUE ) intEnd = TRUE; // space
	if ( (theKeys[1] >> 28) & 0x01 == TRUE ) intEnd = TRUE; // enter
	if ( Button() == TRUE ) intEnd = TRUE; // mouse button
	
	// Adjust you velocity due to key presses.
	if ( ((theKeys[0] >> 0) & 0x01) == TRUE )	velocity += 128; // key pressed is +
	if ( ((theKeys[0] >> 3) & 0x01) == TRUE )	velocity -= 128; // key pressed is -
	
	// Adjust the angle you are looking in.
	angle -= ((xres2 - mx2) >> 3);
	if ( angle > 2559 )	angle -= 2560;
	if ( angle <   0 )	angle += 2560;

	if ( ( theKeys[1] & 0x01 ) == FALSE ) // Is shift pressed?
		{								  // No, then direction and height can change.
			hhhh -= ((yres2 - my2));	  // This line changes your altitude.  
			cxxxx = ((cs[angle] * velocity) >> 8);
			cyyyy = ((sn[angle] * velocity) >> 8);
		}

		// Move you around in the x,y plane.
		xxxx += cxxxx;
		yyyy += cyyyy;

		yOffSet = (yres2 - my2) >> 1;

// These lines make sure you don't go underground.
tempHeight = ((long)(the->map[(short)((yyyy >> 8) & 255)][(short)((xxxx >> 8) & 255)] + 4) << heightShift);
if (hhhh < tempHeight) hhhh = tempHeight;
				
				// Call the drawing routines.
				if (xStep == 1) ToDrawX1();
				if (xStep == 2) ToDrawX2();
				if (xStep == 4) ToDrawX4();
			}
	}
}

void fixVars(void)
{
	angle	=	0;
	rBts	=	(long)(theScreen.rowBytes);
	xres2	=	(long)((theScreen.resolutionX) >> 1);
	yres2	=	(long)((theScreen.resolutionY) >> 1);
	theSize	=	windX * windY;
	orfset	= (xres2 - windX) + ((yres2 - windY) * rBts);
	windX2	=	windX << 1;
	windY2	=	windY << 1;
	windX4	=	windX2 << 1;
	windYsteps = windY2 / yStep;
	windXstep = yStep * windX2;
	velocity = 256;
}

void Maketables(void)
{
long	cnt;
float	num;
	
long colr, shady, depth;
long colorPtr;
long shaded, shaded2;

DialogPtr	dialog;
	
dialog = GetNewDialog(134, nil, (WindowPtr)-1);
DrawDialog(dialog);

// Make cosing and sine tables.
for (cnt = 0; cnt < 2560; cnt++ )
	{
	num	= (float)cnt * 0.00245436926062;
	cs[cnt] = (long)(cos(num) * 256);
	sn[cnt] = (long)(sin(num) * 256);
	}

the3 = (aColPeek)theTemp3;

// Make color tables.
for (colr = 0;colr < 16; colr++)
{
	for (shady = 0;shady < 16; shady++)
	{
		colorPtr = (colr << 4) + shady;
		for (depth = 0;depth < rayLen; depth ++)
		{
			shaded  = ((shady << 2) - ((shady  * depth) >> 7));
			shaded2 = shaded & 1;  //Shaded2 is used for dithering
			shaded  = shaded >> 1;
			shaded2 += shaded;
			if (shaded2 > 31) shaded2 = 31;

			shaded  += ( colr << 5 );
			shaded2 += ( colr << 5 );
			
			shaded += ( shaded2 << 8 );
			shaded += ( shaded << 16 );
			the3->colorGrid[(short)colorPtr][(short)depth] = (unsigned long)shaded;
		}
	}
}

DisposDialog(dialog);

}

void ToolBoxInit(void)
{
	InitGraf(&qd.thePort);
	InitFonts();
	FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(NIL_POINTER);
	InitCursor();
	
	theScreen = GetVideoInfo();
	ScrnBase = theScreen.screenBase;
}

void WindowInit(void)
{
DialogPtr	dialog;
Boolean	itsDone;
short	itemHit;
Rect	theRect, theGameRect;

oldBitDepth = theScreen.bitsPerPixel;

	if (theScreen.BitDepthPossible[8] == FALSE) DoError( 17, TRUE); // Am I in an 8bit mode?

	// Can I do an 8bit mode? and if so can I change?
	if ((theScreen.bitsPerPixel != 8) && (theScreen.BitDepthPossible[8] == TRUE))
							{
								SysBeep(1);
								dialog = GetNewDialog(132, nil, (WindowPtr)-1);
								if (dialog == 0) DoError(4 ,TRUE);
								SetPort( dialog );
								DrawDialog(dialog);
								PenMode( 0 );
								PenSize( 3, 3 );
								theRect = GetDRect( dialog, 5 );
								FrameRoundRect( &theRect, 16, 16 );
								
itsDone = FALSE;
FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
			while(!itsDone)
			{
				ModalDialog(nil, &itemHit);
				if (itemHit == 1) 	{
									ChangeBitDepth(8,1);
									theScreen = GetVideoInfo();
									itsDone = TRUE;
									}
									
				if (itemHit == 2) 	{
									ExitToShell();
									}
							}
			DisposDialog(dialog);
			}

	// Lets open some windows starting with the background then the foreground.
	BackWindow = NewCWindow( 0L, &theScreen.screenRect, "\pFractal", TRUE, plainDBox, ( WindowPtr ) -1, FALSE, 0L );
	SelectWindow(BackWindow);
	SetPort(BackWindow);
	
SetRect(&theGameRect, 0, 0, (windX << 1), (windY << 1));

	theGameWindow = NewCWindow(nil, &theGameRect, "\pFractal", TRUE, 1, (WindowPtr)-1, FALSE, 0);
	MoveWindow(theGameWindow, 	(theScreen.resolutionX >>1) - windX, 
								(theScreen.resolutionY >>1) - windY, FALSE);

	FillWindowsBlack( );

	fracCols = GetNewPalette( (127 + pNum) );
}

void	WindowMove(void)
{
Rect theGameRect;

	qd.randSeed = randSeed;
	
	SelectWindow(BackWindow);
	SetPort(BackWindow);
	
	SetRect( &theGameRect, 0, 0, (windX << 1), (windY << 1) );
	SizeWindow( theGameWindow, (windX << 1), (windY << 1), TRUE );

	MoveWindow(theGameWindow, 	(theScreen.resolutionX >>1) - windX, 
								(theScreen.resolutionY >>1) - windY, FALSE );

	DisposePalette(fracCols);
	fracCols = GetNewPalette( (127 + pNum) );
	SetPalette( BackWindow, fracCols, TRUE );
	SetPalette( theGameWindow, fracCols, TRUE );
	
	FillWindowsBlack( );

	SelectWindow(theGameWindow);
	SelectWindow(theGameWindow);
}

void MemInit(void)
{
Size	ScSize;

	theTemp		= 	NewPtr( 66049 );
	if (theTemp == 0) DoError(6, TRUE);

	theTemp2	= 	NewPtr( 66049 );
	if (theTemp2 == 0) DoError(6, TRUE);

ScSize = (Size)(((long)theScreen.resolutionX) * ((long)theScreen.resolutionY));

	offScreen	=	NewPtr( ScSize );
	if (offScreen == 0) DoError(6, TRUE);
	
	theTemp3 = NewPtr( 524288 );
	if (theTemp3 == 0) DoError(6, TRUE);
	
	the = (mapPeek)theTemp;
	the2 = (mapPeek)theTemp2;
}

void MemEnd(void)
{
	DisposPtr(theTemp);
	DisposPtr(theTemp2);
	DisposPtr(theTemp3);
	DisposPtr(offScreen);
}

void FillWindowsBlack( void )
{
	SetPort(BackWindow);
	ForeColor( blackColor );
	PaintRect( &BackWindow->portRect );
	SetPort(theGameWindow);
	ForeColor( blackColor );
	PaintRect( &theGameWindow->portRect );
}

void MakeMap(void)
{
	short 	pss,height;
	short		x,y;
	
	DialogPtr	dialog;

	dialog = GetNewDialog(129, nil, (WindowPtr)-1);
	DrawDialog(dialog);
	FillWindowsBlack( );

	qd.randSeed = randSeed;
		
	pss =		64;
	height =	128;
	
	for( y = 0; y < mapY; y++ )
	{
		for( x = 0; x < mapX; x++ )
		{
			the->map[x][y] = 128;
		}
	}
				
	while( pss > ( 20 - ( 4 * roughness ) ) )
	{
		ChangeHeight( pss, height );
		Smooth(pss);
		pss = pss >> 1;
		height = height >> 1;
		if (height == 0) height = 1;
	}
	
	while(pss > 1)
	{
		Smooth(pss);
		pss = pss >> 1;
	}

	DisposDialog(dialog);
}

void ChangeHeight( int pss, int height )
{
	long			x,y;

	for ( x = 0; x < mapX; x = x + pss )
	{
		for( y = 0; y < mapY; y = y + pss )
		{
			the->map[x][y] = the->map[x][y] + (((long)Random() * height) >> (17 - maxHeight) );
		}
	}
	
}

void Smooth(int pss)
{
	long		dff;
	short		x,y;
	long	misc;

	dff = pss>>1;
	for ( x = 0; x < mapX; x = x + pss )
	{
		for( y = 0; y < mapY; y = y + pss )
		{	
		
	misc = (long)((long)hght(x,y) + (long)hght(x + pss,y) + (long)hght(x + pss,y + pss) + (long)hght(x,y + pss));
	
	the->map[x+dff][y+dff] = (unsigned char)(misc >> 2);
	
	the->map[x+dff][y] = (hght(x,y) + hght(x+pss,y)) >> 1;
	
	the->map[x][y+dff] = (hght(x,y) + hght(x,y+pss)) >> 1;

	the->map[x+pss][y+dff] = ((long)((hght(x+pss,y+pss) + hght(x+pss,y)))) >> 1;

	the->map[x+dff][y+pss] = ( hght(x+pss,y+pss) + hght(x,y+pss)) >> 1;
			
		}
	}
}

int hght(short x, short y)
{

return (unsigned char)the->map[x & mapXp][y & mapYp];
}

int hght2(short x, short y)
{

return (unsigned char)the2->map[x & mapXp][y & mapYp];
}

void BlurMap(void)
{
long	hht;
short	x,y;

	DialogPtr	dialog;
	
	dialog = GetNewDialog(130, nil, (WindowPtr)-1);
	DrawDialog(dialog);
	FillWindowsBlack( );

for(x = 0; x < mapX; x++)
	{
		for(y = 0; y < mapY; y++)
			{
				hht = the->map[x][y];
				
				hht -= waterLevel;
				if (hht < 0) hht = 0;
				the2->map[x][y] = hht;
			}
	}

for(x = 0; x < mapX; x++)
	{
		for(y = 0; y < mapY; y++)
			{
				hht = (long)(((long)hght2(x+6,y-4)) << 2) + (((long)hght2(x-4,y+8)) << 2) + ((long)(hght2(x,y)) << 3);
				the->map[x][y] = (unsigned char)(hht >> 5);
			}
	}

	DisposDialog(dialog);
}

void MakeCols(void)
{
	short	x, y, c, co;
	
	DialogPtr	dialog;
	
	dialog = GetNewDialog(131, nil, (WindowPtr)-1);
	DrawDialog(dialog);
	FillWindowsBlack( );
	
	for( y = 0; y < mapX; y++)
	{
		for( x = 0; x < mapY; x++)
		{
			c = (short)(the->map[x][y]);
			co = c;
				c = (short)( (long)(c - 
							((unsigned char)the->map
								[((short)(x + 3) & mapXp)]
								[((short)(y + 3) & mapYp)])
						));
			 	c = (c >> 1) + 7;
			 	if (c > 15) c = 15;
			 	if (c < 0) c = 0;
			 	
			 	c += 32;
			 	
			 	if (co == 0) c = 47;
			 	if (co > 0) c = c + 16;
			 	if (co > 16) c = c + 16;
			 	if (co > 32) c = c + 16;
			 	if (co > 48) c = c + 16;
			 				 	
			 	the2->map[x][y] = (unsigned char)(c);
		}
	}

	DisposDialog(dialog);
	FillWindowsBlack( );
}

#if GENERATING68K

asm copyOffScreen(void)
{
	move.l	offScreen, a0
	add.l	windXstep, a0
	sub.l	windX2, a0
	move.l	ScrnBase, a1
	add.l	orfset, a1
	
	move.l	windYsteps, d1
	move.l	windX, d0
	asr.l	#1, d0
	sub.l	#1, d0
	sub.l	#1, d1
	
	asr		#2, d0
	move.l	d0, d2

	move.l	rBts, d3
	sub.l	windX2, d3

	@4:
	move.l	yStep, d7
	sub.l	#1, d7
	
		@50:
		move.l	d2, d0
				
			@5:
			move.l	(a0)+, (a1)+
			move.l	(a0)+, (a1)+
			move.l	(a0)+, (a1)+
			move.l	(a0)+, (a1)+
			dbra	d0, @5
	
		sub.l	windX2, a0	/* for copy same line */
		add.l	d3, a1		/* where d3 is diff. between windowXsize and RowBytes */
	
		dbra	d7,@50	

	add.l	windXstep, a0
	dbra	d1,@4
	
rts
}

#else

void copyOffScreen(void)
{
Ptr	ta0, ta1, ta2;
long td0, td1, td2, td3, td7;	

ta0 = offScreen;
ta0 += windXstep;
ta0 -= windX2;
ta1 = ScrnBase;
ta1+= orfset;

td1 = windYsteps;
td0 = (windX >> 1);
td0 -= 1;
td1 -= 1;

td2 = td0;

td3 = rBts - windX2;

while(td1 >= 0)
	{
		td7 = yStep - 1;
		
		while(td7 >= 0)
			{
				td0 = td2;
				
				ta2 = ta0 + (4 * td2);
				
				while(ta2 >= ta0)
					{
						*(unsigned long*)(ta1) = *(unsigned long*)(ta0);
						ta0 += 4;
						ta1 += 4;
					}
				ta0 -= windX2;
				ta1 += td3;
				
				td7 -= 1;
			}
		ta0 += windXstep;
		td1 -= 1;
	}
}

#endif

#if GENERATING68K

asm clearOffScreen(void)
{
	move.l	offScreen, a0
	move.l	theSize, d0
	move.l	#514 , d1
	move.l	d1, d2
	swap	d2
	add.l	d2, d1

	@1:
	move.l	d1, (a0)+
	move.l	d1, (a0)+
	move.l	d1, (a0)+
	move.l	d1, (a0)+
	sub.l	#4, d0
	bne	@1
	rts
}

#else

void clearOffScreen(void)
{
Ptr	offScreenCounter;
Ptr	theEndCounter;
unsigned long	skyColour;

offScreenCounter = offScreen;
theEndCounter = offScreenCounter + (theSize << 2);
skyColour = 514 + ( 514 << 16 );

while(theEndCounter != offScreenCounter)
	{
		*(unsigned long*)(offScreenCounter) = skyColour;
		offScreenCounter +=4;
	}
}

#endif

void ToDrawX1(void)
{
long 	xp, yp, xp2;
long	L;
long	x, y;
long	xv, zv;
long	z, yv;
Ptr		offScreen2;
unsigned short	MrBlobby;
long	rayLenTmp;
long	xOffSet, xOffSetdiv, xChng, yztemp, yOffSet2;

xp 	= -windX;
xp2	= 0;
xChng = -((xres2 - mx2) >> 2);
xOffSet = xp * xChng;
xOffSetdiv = xOffSet >> 8;

while (xp < windX)
	{

	x	=	xxxx;
	y	=	yyyy;
	z	=	hhhh + (xOffSet >> 8);

	yp	= 	-windY;
	L	=  	0;
	offScreen2 = offScreen + xp2 + (((windY2-1) * windX2));
	
	xv	=	(long)(cs[angle] - ((xp * sn[angle]) >> 8) );
	zv	=	(long)(sn[angle] + ((xp * cs[angle]) >> 8) );

	yv	=	yp - yOffSet - (xOffSet >> 8);
	yOffSet2 = - yOffSet - xOffSetdiv;

	rayLenTmp = 128;
	if (rayLen < rayLenTmp) rayLenTmp = rayLen;
	MrBlobby = mrBlob1;

	while (L<rayLenTmp)
		{						
	
		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(char*)(offScreen2) = 
			*(char*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));

			yp += yStep;
			if (yp >= windY) goto end3;	
	
			offScreen2	-= windXstep;
			yv += yStep;

			z = hhhh + (yv * L);

			}
			else
			{
				L++;
				z += yv;
				x += xv;
				y += zv;
				MrBlobby = mrBlob1;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = 256;
		if (rayLen < rayLenTmp) rayLenTmp = rayLen;
		
		if (yp>=windY) L = rayLenTmp;

		yztemp = yp + yOffSet2;

		while ( L < rayLenTmp )
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(char*)(offScreen2) = 
			*(char*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp	+= yStep;
			if (yp >= windY) goto end3;
						
			offScreen2	-= windXstep;

			yztemp += yStep;
			yv = yztemp << 1;
			
			z = hhhh + (yztemp * L);

			}
			else
			{
				L += 2;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob2;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = rayLen;
		
		if (yp>=windY) goto end3;
		
		yztemp = yp + yOffSet2;

		while (L<rayLenTmp)
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(char*)(offScreen2) = 
			*(char*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp += yStep;
			if (yp >= windY) goto end3;
			
			offScreen2	-= windXstep;
						
			yztemp += yStep;
			yv	=	yztemp << 2;
			
			z = hhhh + (yztemp * L);
			}
			else
			{
				L += 4;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob3;
			}
		}
		
	end3:
	xp2	+= 1;
	xp	+= 1;
	xOffSet += xChng;
	xOffSetdiv = xOffSet >> 8;
	}
	copyOffScreen();
	clearOffScreen();
}

void ToDrawX2(void)
{
long 	xp, yp, xp2;
long	L;
long	x, y;
long	xv, zv;
long	z, yv;
Ptr		offScreen2;
unsigned short	MrBlobby;
long	rayLenTmp;
long	xOffSet, xOffSetdiv, xChng, yztemp, yOffSet2;

xp 	= -windX;
xp2	= 0;
xChng = -((xres2 - mx2) >> 2);
xOffSet = xp * xChng;
xOffSetdiv = xOffSet >> 8;
xChng = xChng << 1;

while (xp < windX)
	{

	x	=	xxxx;
	y	=	yyyy;
	z	=	hhhh + (xOffSet >> 8);

	yp	= 	-windY;
	L	=  	0;
	offScreen2 = offScreen + xp2 + (((windY2-1) * windX2));
	
	xv	=	(long)(cs[angle] - ((xp * sn[angle]) >> 8) );
	zv	=	(long)(sn[angle] + ((xp * cs[angle]) >> 8) );

	yv	=	yp - yOffSet - (xOffSet >> 8);
	yOffSet2 = - yOffSet - xOffSetdiv;

	rayLenTmp = 128;
	if (rayLen < rayLenTmp) rayLenTmp = rayLen;
	MrBlobby = mrBlob1;

	while (L<rayLenTmp)
		{						
	
		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(short*)(offScreen2) = 
			*(short*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));

			yp += yStep;
			if (yp >= windY) goto end3;	
	
			offScreen2	-= windXstep;
			yv += yStep;

			z = hhhh + (yv * L);

			}
			else
			{
				L++;
				z += yv;
				x += xv;
				y += zv;
				MrBlobby = mrBlob1;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = 256;
		if (rayLen < rayLenTmp) rayLenTmp = rayLen;
		
		if (yp>=windY) L = rayLenTmp;

		yztemp = yp + yOffSet2;

		while ( L < rayLenTmp )
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(short*)(offScreen2) = 
			*(short*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp	+= yStep;
			if (yp >= windY) goto end3;
						
			offScreen2	-= windXstep;

			yztemp += yStep;
			yv = yztemp << 1;
			
			z = hhhh + (yztemp * L);

			}
			else
			{
				L += 2;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob2;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = rayLen;
		
		if (yp>=windY) goto end3;
		
		yztemp = yp + yOffSet2;

		while (L<rayLenTmp)
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(short*)(offScreen2) = 
			*(short*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp += yStep;
			if (yp >= windY) goto end3;
			
			offScreen2	-= windXstep;
						
			yztemp += yStep;
			yv	=	yztemp << 2;
			
			z = hhhh + (yztemp * L);
			}
			else
			{
				L += 4;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob3;
			}
		}
	
	end3:
	xp2	+= 2;
	xp	+= 2;
	xOffSet += xChng;
	xOffSetdiv = xOffSet >> 8;
	}
	copyOffScreen();
	clearOffScreen();
}

void ToDrawX4(void)
{
long 	xp, yp, xp2;
long	L;
long	x, y;
long	xv, zv;
long	z, yv;
Ptr		offScreen2;
unsigned short	MrBlobby;
long	rayLenTmp;
long	xOffSet, xOffSetdiv, xChng, yztemp, yOffSet2;

xp 	= -windX;
xp2	= 0;
xChng = -((xres2 - mx2) >> 2);
xOffSet = xp * xChng;
xOffSetdiv = xOffSet >> 8;
xChng = xChng << 2;

while (xp < windX)
	{

	x	=	xxxx;
	y	=	yyyy;
	z	=	hhhh + (xOffSet >> 8);

	yp	= 	-windY;
	L	=  	0;
	offScreen2 = offScreen + xp2 + (((windY2-1) * windX2));
	
	xv	=	(long)(cs[angle] - ((xp * sn[angle]) >> 8) );
	zv	=	(long)(sn[angle] + ((xp * cs[angle]) >> 8) );

	yv	=	yp - yOffSet - (xOffSet >> 8);
	yOffSet2 = - yOffSet - xOffSetdiv;

	rayLenTmp = 128;
	if (rayLen < rayLenTmp) rayLenTmp = rayLen;
	MrBlobby = mrBlob1;

	while (L<rayLenTmp)
		{						
	
		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(long*)(offScreen2) = 
			*(long*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));

			yp += yStep;
			if (yp >= windY) goto end3;	
	
			offScreen2	-= windXstep;
			yv += yStep;

			z = hhhh + (yv * L);

			}
			else
			{
				L++;
				z += yv;
				x += xv;
				y += zv;
				MrBlobby = mrBlob1;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = 256;
		if (rayLen < rayLenTmp) rayLenTmp = rayLen;
		
		if (yp>=windY) L = rayLenTmp;

		yztemp = yp + yOffSet2;

		while ( L < rayLenTmp )
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(unsigned long*)(offScreen2) = 
			*(unsigned long*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp	+= yStep;
			if (yp >= windY) goto end3;
						
			offScreen2	-= windXstep;

			yztemp += yStep;
			yv = yztemp << 1;
			
			z = hhhh + (yztemp * L);

			}
			else
			{
				L += 2;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob2;
			}
		}
		
		yv	=	yv << 1;
		xv	=	xv << 1;
		zv	=	zv << 1;
		
		rayLenTmp = rayLen;
		
		if (yp>=windY) goto end3;
		
		yztemp = yp + yOffSet2;

		while (L<rayLenTmp)
		{

		if ( *(unsigned char*)(theTemp + MrBlobby ) > (z >> heightShift) )
			{
			*(unsigned long*)(offScreen2) = 
			*(unsigned long*)(theTemp3 + (((long)*(theTemp2 + MrBlobby)) << 11) + (L << 2));
			
			yp += yStep;
			if (yp >= windY) goto end3;
			
			offScreen2	-= windXstep;
						
			yztemp += yStep;
			yv	=	yztemp << 2;
			
			z = hhhh + (yztemp * L);
			}
			else
			{
				L += 4;
				x += xv;
				y += zv;
				z += yv;
				MrBlobby = mrBlob3;
			}
		}

	end3:
	xp2	+= 4;
	xp	+= 4;
	xOffSet += xChng;
	xOffSetdiv = xOffSet >> 8;
	}

	copyOffScreen();
	clearOffScreen();
}

void DoPreferences(void)
{
Boolean 		itsDone;
DialogPtr		theDialog, theDialog2;
short			itemHit, itemHit2;
Rect			iRect;
Point 			tempPoint;
Rect			tempRect;
StringHandle	string;

short			WindowSizeError, WindowSizeTemp;
short			PixelSizeError, PixelSizeTemp;
short			LandScapeError, LandScapeTemp;
short			RayLenError, RayLenTemp;
short			keyBoardTemp, keyBoardError;
short			heightTemp, heightError;
short			roughTemp, roughError;

ControlHandle	WindSizeCtrl, PixSizeCtrl, LandCtrl, RayLenCtrl, ctrlCtrl, heightCtrl, roughCtrl;
MenuHandle		WindSizeMenu, LandMenu, PixSizeMenu, RayLenMenu, ctrlMenu, heightMenu, roughMenu;

ShowCursor();

string = NewHandle( 256 );

theDialog = GetNewDialog(133, nil, BackWindow);

if (theDialog == 0) DoError(4 ,TRUE);

SetPort( theDialog );

SelectWindow( theDialog );
BringToFront( theDialog );
DrawDialog( theDialog );

PenMode( 0 );
PenSize( 3, 3 );
tempRect = GetDRect( theDialog, 21 );
FrameRoundRect( &tempRect, 16, 16 );

tempRect = GetDRect(theDialog, mWindSize);
WindSizeCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, WindSizeMnu, 0, (1008 + 5), WindSizeMnu);
if (WindSizeCtrl == 0) DoError(18 ,TRUE);

WindSizeMenu = GetMenu(WindSizeMnu);
if (WindSizeMenu == 0) DoError(1 ,TRUE);
InsertMenu(WindSizeMenu, -1);

tempRect = GetDRect(theDialog, mHeight);
heightCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, heightMnu, 0, (1008 + 5), WindSizeMnu);
if (heightCtrl == 0) DoError(18 ,TRUE);

heightMenu = GetMenu(heightMnu);
if (heightMenu == 0) DoError(1 ,TRUE);
InsertMenu(heightMenu, -1);

tempRect = GetDRect(theDialog, mRough);
roughCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, roughMnu, 0, (1008 + 5), WindSizeMnu);
if (roughCtrl == 0) DoError(18 ,TRUE);

roughMenu = GetMenu(roughMnu);
if (roughMenu == 0) DoError(1 ,TRUE);
InsertMenu(roughMenu, -1);

tempRect = GetDRect( theDialog, mCtrl );
ctrlCtrl = NewControl( theDialog, &tempRect, "", TRUE, 1, CtrlMnu, 0, (1008 + 5), WindSizeMnu );
if (ctrlCtrl == 0) DoError(18 ,TRUE);

ctrlMenu = GetMenu( CtrlMnu );
if ( ctrlMenu == 0 ) DoError( 1 ,TRUE );
InsertMenu(ctrlMenu, -1);

if (theScreen.resolutionX < 640) DisableItem(WindSizeMenu, 6);
if (theScreen.resolutionX < 640) DisableItem(WindSizeMenu, 5);
if (theScreen.resolutionX < 512) DisableItem(WindSizeMenu, 4);
if (theScreen.resolutionX < 400) DisableItem(WindSizeMenu, 3);
if (theScreen.resolutionX < 320) DisableItem(WindSizeMenu, 2);
if (theScreen.resolutionX < 160) DisableItem(WindSizeMenu, 1);

if (theScreen.resolutionY < 480) DisableItem(WindSizeMenu, 6);
if (theScreen.resolutionY < 400) DisableItem(WindSizeMenu, 5);
if (theScreen.resolutionY < 384) DisableItem(WindSizeMenu, 4);
if (theScreen.resolutionY < 300) DisableItem(WindSizeMenu, 3);
if (theScreen.resolutionY < 240) DisableItem(WindSizeMenu, 2);
if (theScreen.resolutionY < 120) DisableItem(WindSizeMenu, 1);

tempRect = GetDRect(theDialog, mPixelSize);
PixSizeCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, PixSizeMnu, 0, (1008 + 5), WindSizeMnu);
if (PixSizeCtrl == 0) DoError(18 ,TRUE);

PixSizeMenu = GetMenu(PixSizeMnu);
if (PixSizeMenu == 0) DoError(1 ,TRUE);
InsertMenu(PixSizeMenu, -1);

tempRect = GetDRect(theDialog, mLandscape);
LandCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, LandMnu, 0, (1008 + 5), WindSizeMnu);
if (LandCtrl == 0) DoError(18 ,TRUE);

LandMenu = GetMenu(LandMnu);
if (LandMenu == 0) DoError(1 ,TRUE);
InsertMenu(LandMenu, -1);

tempRect = GetDRect(theDialog, mRayLength);
RayLenCtrl = NewControl(theDialog, &tempRect, "", TRUE, 1, RayLenMnu, 0, (1008 + 5), WindSizeMnu);
if (RayLenCtrl == 0) DoError(18 ,TRUE);

RayLenMenu = GetMenu(RayLenMnu);
if (RayLenMenu == 0) DoError(1 ,TRUE);
InsertMenu(RayLenMenu, -1);

SetTheInfo(theDialog, tRandSeed, randSeed);
SetTheInfo(theDialog, tWaterLevel, waterLevel);

SetCtlValue( PixSizeCtrl , (short)PixelSizeOption );
SetCtlValue( WindSizeCtrl, (short)WindowSizeOption );
SetCtlValue( LandCtrl    , (short)LandScapeOption );
SetCtlValue( RayLenCtrl  , (short)RayLengthOption );
SetCtlValue( ctrlCtrl    , (short)keyBoard );
SetCtlValue( heightCtrl  , (short)maxHeight );
SetCtlValue( roughCtrl   , (short)roughness );

tempRect = GetDRect( theDialog, 24);
FrameRect(&tempRect);
tempRect = GetDRect( theDialog, 29);
FrameRect(&tempRect);

itsDone = FALSE;

FlushEvents(everyEvent, REMOVE_ALL_EVENTS);

	while(!itsDone)
	{
		ModalDialog(nil, &itemHit);
		if (itemHit == bOK) 	{
								itsDone = TRUE;
								}
		
		if (itemHit == bQuit) 	{
								Quit();
								}

		if (itemHit == bAbout) 	{
								FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
								theDialog2 = GetNewDialog(8000, nil, BackWindow);
								SelectWindow(theDialog2);
								BringToFront(theDialog2);
								SetPort( theDialog2 );
								PenMode( 0 );
								PenSize( 3, 3 );
								tempRect = GetDRect( theDialog2, 4 );
								FrameRoundRect( &tempRect, 16, 16 );
								itemHit2 = 0;
								while(itemHit2 != 1) { ModalDialog(nil, &itemHit2); }
								DisposDialog(theDialog2);
								SetPort( theDialog );
								FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
								tempRect = GetDRect( theDialog, 24);
								FrameRect(&tempRect);
								tempRect = GetDRect( theDialog, 29);
								FrameRect(&tempRect);
								}

		if (itemHit == bRandomize){
								qd.randSeed = (unsigned long)TickCount();
								randSeed = Random() + 32767;
								if (randSeed == 0) randSeed = 1;
								SetTheInfo(theDialog, tRandSeed, randSeed);
								}

		if (itemHit == mWindSize){
									WindowSizeError = WindowSizeOption;
									iRect = GetDRect(theDialog, mWindSize);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									WindowSizeTemp = PopUpMenuSelect(WindSizeMenu, tempPoint.v, tempPoint.h, WindowSizeOption);
									if (WindowSizeTemp != 0) WindowSizeOption = WindowSizeTemp;
									if (WindowSizeTemp == 8) {
																DoOther();
																SetPort(theDialog);
																tempRect = GetDRect( theDialog, 18);
																FrameRect(&tempRect);
															 }
									SetCtlValue(WindSizeCtrl, (short)WindowSizeOption);
								}

		if (itemHit == mPixelSize){
									PixelSizeError = PixelSizeOption;
									iRect = GetDRect(theDialog, mPixelSize);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									PixelSizeTemp = PopUpMenuSelect(PixSizeMenu, tempPoint.v, tempPoint.h, PixelSizeOption);
									if (PixelSizeTemp != 0) PixelSizeOption = PixelSizeTemp;
									SetCtlValue(PixSizeCtrl, (short)PixelSizeOption);
								}

		if (itemHit == mCtrl){
									keyBoardError = keyBoard;
									iRect = GetDRect(theDialog, mCtrl);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									keyBoardTemp = PopUpMenuSelect( ctrlMenu, tempPoint.v, tempPoint.h, keyBoard);
									if (keyBoardTemp != 0) keyBoard = keyBoardTemp;
									SetCtlValue(ctrlCtrl, (short)keyBoard);
								}

		if (itemHit == mHeight){
									heightError = maxHeight;
									iRect = GetDRect(theDialog, mHeight);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									heightTemp = PopUpMenuSelect( heightMenu, tempPoint.v, tempPoint.h, maxHeight );
									if (heightTemp != 0) maxHeight = heightTemp;
									SetCtlValue(heightCtrl, (short)maxHeight);
								}

		if (itemHit == mRough){
									roughError = roughness;
									iRect = GetDRect(theDialog, mRough);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									roughTemp = PopUpMenuSelect( roughMenu, tempPoint.v, tempPoint.h, roughness );
									if (roughTemp != 0) roughness = roughTemp;
									SetCtlValue(roughCtrl, (short)roughness);
								}

		if (itemHit == mLandscape){
									LandScapeError = LandScapeOption;
									iRect = GetDRect(theDialog, mLandscape);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									LandScapeTemp = PopUpMenuSelect(LandMenu, tempPoint.v, tempPoint.h, LandScapeOption);
									if (LandScapeTemp != 0) LandScapeOption = LandScapeTemp;
									SetCtlValue(LandCtrl, (short)LandScapeOption);
								}

		if (itemHit == mRayLength){
									RayLenError = RayLengthOption;
									iRect = GetDRect(theDialog, mRayLength);
									tempPoint.v = iRect.top;
									tempPoint.h = iRect.left;
									LocalToGlobal(&tempPoint);
									RayLenTemp = PopUpMenuSelect(RayLenMenu, tempPoint.v, tempPoint.h, RayLengthOption);
									if (RayLenTemp != 0) RayLengthOption = RayLenTemp;
									SetCtlValue(RayLenCtrl, (short)RayLengthOption);
								}
	}

GetTheInfoStr(theDialog, tRandSeed, string);
StringToNum(*string, &randSeed);

GetTheInfoStr(theDialog, tWaterLevel, string);
StringToNum(*string, &waterLevel);

if (randSeed == 0) randSeed = 1;

tempPoint.v = 0;
tempPoint.h = 0;
ShieldCursor(&theScreen.screenRect, tempPoint);

DisposHandle(string);

switch (WindowSizeOption) {

				case 1:	{	windX = 80;
							windY = 60;
						} 	break;

				case 2:	{	windX = 160;
							windY = 120;
						} 	break;

				case 3:	{	windX = 200;
							windY = 150;
						} 	break;

				case 4:	{	windX = 256;
							windY = 192;
						} 	break;

				case 5:	{	windX = 320;
							windY = 200;
						} 	break;

				case 6:	{	windX = 320;
							windY = 240;
						} 	break;
						
						}

switch (PixelSizeOption) {

				case 1:	{	xStep = 1;
							yStep = 1;
						} 	break;

				case 2:	{	xStep = 2;
							yStep = 1;
						} 	break;

				case 3:	{	xStep = 2;
							yStep = 2;
						} 	break;

				case 4:	{	xStep = 4;
							yStep = 2;
						} 	break;

				case 5:	{	xStep = 4;
							yStep = 4;
						} 	break;
						
						}
						
switch (RayLengthOption) {

				case 1:	{	rayLen = 128;
						} 	break;

				case 2:	{	rayLen = 200;
						} 	break;

				case 3:	{	rayLen = 256;
						} 	break;

				case 4:	{	rayLen = 320;
						} 	break;

				case 5:	{	rayLen = 400;
						} 	break;

				case 6:	{	rayLen = 512;
						} 	break;

						}
pNum = LandScapeOption;

DisposDialog(theDialog);
FillWindowsBlack( );
}

void DoOther(void)
{
DialogPtr	dialog;
short	itemHit;
Boolean itsDone;
short	windXtemp, windYtemp;
Rect	theRect;

FlushEvents(everyEvent, REMOVE_ALL_EVENTS);

dialog = GetNewDialog(128, nil, BackWindow);
if (dialog == 0) DoError(4 ,TRUE);

SetTheInfo(dialog, 3, windX2);
SetTheInfo(dialog, 4, windY2);
SelectWindow(dialog);

BringToFront( dialog );
DrawDialog( dialog );
SetPort( dialog );

PenMode( 0 );
PenSize( 3, 3 );
theRect = GetDRect( dialog, 6 );
FrameRoundRect( &theRect, 16, 16 );

itsDone = FALSE;

while(itsDone != TRUE) {

ModalDialog(nil, &itemHit);

	switch (itemHit) {
	
					case bOK:	{
									windXtemp = GetTheInfo(dialog, 3);
									if (windXtemp > theScreen.resolutionX) windXtemp = theScreen.resolutionX;
									windYtemp = GetTheInfo(dialog, 4);
									if (windYtemp > theScreen.resolutionY) windYtemp = theScreen.resolutionY;
									windXtemp = windXtemp >> 5 << 5;
									windYtemp = windYtemp >> 2 << 2;
									if (windXtemp == 0) windXtemp = 32;
									if (windYtemp == 0) windYtemp = 32;
									windX = windXtemp >> 1;
									windY = windYtemp >> 1;
									itsDone = TRUE;
								}
			
					case bQuit: {
									itsDone = TRUE;
								}
					}
}

DisposDialog(dialog);
FillWindowsBlack( );
FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
}

void Quit(void)
{
	ShowCursor();
	ShowMenuBar();
	MemEnd();
	FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
	ChangeBitDepth(oldBitDepth,1);
	ExitToShell();
}