/*
 *  Copyright (c) 1993 Michael D. Bayne.
 *  All rights reserved.
 *
 *  Please see the documentation accompanying the distribution for
 *  distribution and disclaimer information.
 */

#define V39 ( ExecBase->LibNode.lib_Version > 38 )

#ifdef SCRMODEREQ
#include <libraries/reqtools.h>
#include <clib/reqtools_protos.h>
#include <pragmas/reqtools_pragmas.h>
#include <libraries/asl.h>
#include <clib/asl_protos.h>
#include <pragmas/asl_pragmas.h>

VOID ScreenModeRequest( struct Window *Wnd, LONG *Mode, LONG *Depth )
{
	struct AslBase *AslBase;
	
	if( AslBase = ( struct AslBase * )OpenLibrary( AslName, 38L ))
	{
		struct ScreenModeRequester *smRequest;
		
		if( smRequest = AllocAslRequestTags( ASL_ScreenModeRequest, TAG_END ))
		{
			if( Depth )
			{
				if( AslRequestTags( smRequest, ASLSM_Window, Wnd,
								   ASLSM_SleepWindow, TRUE,
								   ASLSM_TitleText, "Screen Mode",
								   ASLSM_InitialDisplayID, *Mode,
								   ASLSM_InitialDisplayDepth, *Depth,
								   ASLSM_DoDepth, TRUE, TAG_END ))
				{
					*Mode = smRequest->sm_DisplayID;
					*Depth = smRequest->sm_DisplayDepth;
				}
			}
			else
			{
				if( AslRequestTags( smRequest, ASLSM_Window, Wnd,
								   ASLSM_SleepWindow, TRUE,
								   ASLSM_TitleText, "Screen Mode",
								   ASLSM_InitialDisplayID, *Mode, TAG_END ))
					*Mode = smRequest->sm_DisplayID;
			}
			FreeAslRequest( smRequest );
		}
		CloseLibrary(( struct Library * )AslBase );
	}
	else
	{
		struct ReqToolsBase *ReqToolsBase;

		if( ReqToolsBase = ( struct ReqToolsBase * )
		   OpenLibrary( REQTOOLSNAME, REQTOOLSVERSION ))
		{
			struct rtScreenModeRequester *smRequest;
			
			if( smRequest = rtAllocRequestA( RT_SCREENMODEREQ, 0l ))
			{
				if( Depth )
				{
					LONG Tags[] = { RT_Window, 0L, RT_LockWindow, TRUE,
										RTSC_Flags, SCREQF_DEPTHGAD, TAG_END };
					LONG ReqTags[] = { RTSC_DisplayID, 0L,
										   RTSC_DisplayDepth, 0L, TAG_END };
					ReqTags[1] = *Mode;
					ReqTags[3] = *Depth;
					rtChangeReqAttrA( smRequest, ( struct TagItem * )ReqTags );
					
					Tags[1] = ( LONG )Wnd;
					if( rtScreenModeRequestA( smRequest, "Screen Mode",
											 ( struct TagItem * )Tags ))
					{
						*Mode = smRequest->DisplayID;
						*Depth = smRequest->DisplayDepth;
					}
				}
				else
				{
					LONG Tags[] = { RT_Window, 0L, RT_LockWindow, TRUE,
										TAG_END };
					LONG ReqTags[] = { RTSC_DisplayID, 0L, TAG_END };
					
					ReqTags[1] = *Mode;
					rtChangeReqAttrA( smRequest, ( struct TagItem * )ReqTags );
					
					Tags[1] = ( LONG )Wnd;
					if( rtScreenModeRequestA( smRequest, "Screen Mode",
											 ( struct TagItem * )Tags ))
						*Mode = smRequest->DisplayID;
				}
				rtFreeRequest( smRequest );
			}
			CloseLibrary(( struct Library * )ReqToolsBase );
		}
	}
}
#endif

#ifdef COPPERLIST
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/copper.h>
#include <graphics/videocontrol.h>
#include <hardware/custom.h>

__far extern struct Custom custom;
extern struct GfxBase *GfxBase;

VOID setCopperList( LONG height, LONG color, struct ViewPort *vp )
{
#define NUMCOLORS 45
	
	struct UCopList *uCopList;
	struct TagItem uCopTags[] = {{ VTAG_USERCLIP_SET, 0L },
								 { VTAG_END_CM, 0L }};
	register LONG i, index = RangeRand( NUMCOLORS ), spc;
	LONG spectrum[] = {
		0x0F00, 0x0E10, 0x0D20, 0x0C30, 0x0B40, 0x0A50, 0x0960,	0x0870, 0x0780,
		0x0690, 0x05A0, 0x04B0, 0x03C0, 0x02D0,	0x01E0, 0x00F0, 0x00E1, 0x00D2,
		0x00C3, 0x00B4, 0x00A5,	0x0096, 0x0087, 0x0078, 0x0069, 0x005A, 0x004B,
		0x003C,	0x002D, 0x001E, 0x000F, 0x010E, 0x020D, 0x030C, 0x040B,	0x050A,
		0x0609, 0x0708, 0x0807, 0x0906, 0x0A05, 0x0B04,	0x0C03, 0x0D02, 0x0E01
		};
	
	if( uCopList = ( struct UCopList * )AllocMem( sizeof( struct UCopList ),
												 MEMF_PUBLIC|MEMF_CLEAR )) {
		spc = height/NUMCOLORS;
		CINIT( uCopList, NUMCOLORS );
		for( i = 0; i < NUMCOLORS; ++i ) {
			CWAIT( uCopList, i * spc, 0 );
			CMOVE( uCopList, custom.color[color],
				  spectrum[( i + index ) % NUMCOLORS] );
		}
		
		CEND( uCopList );
		
		Forbid();
		vp->UCopIns = uCopList;
		Permit();
		
		VideoControl( vp->ColorMap, uCopTags );
		RethinkDisplay();
	}
}
#endif

#ifdef CLONETOPSCREEN
#define GETTOPSCREENMODE
#define GETTOPSCREENDEPTH
#endif

#ifdef GETTOPSCREENMODE
#include <clib/graphics_protos.h>
#include <intuition/intuitionbase.h>
extern struct IntuitionBase *IntuitionBase;
ULONG getTopScreenMode( void )
{
	BPTR lock;
	struct Screen *pubScr;
	ULONG scrMode;
	
	lock = LockIBase( 0 );
	pubScr = IntuitionBase->FirstScreen;
	scrMode = GetVPModeID(&( pubScr->ViewPort));
	UnlockIBase( lock );
	return( scrMode );
}
#endif

#ifdef GETTOPSCREENDEPTH
#include <clib/graphics_protos.h>
#include <intuition/intuitionbase.h>
extern struct IntuitionBase *IntuitionBase;
ULONG getTopScreenDepth( void )
{
	BPTR lock;
	struct Screen *pubScr;
	struct DrawInfo *dri;
	ULONG sDep = 0;
	
	lock = LockIBase( 0 );
	pubScr = IntuitionBase->FirstScreen;
	if( dri = GetScreenDrawInfo( pubScr )) {
		sDep = dri->dri_Depth;
		FreeScreenDrawInfo( pubScr, dri );
	}
	UnlockIBase( lock );
	return( sDep );
}
#endif

#ifdef CLONETOPSCREEN
#include <exec/execbase.h>
#define ExecBase (*(( struct ExecBase ** )4L ))

#ifndef min
#define min( x, y ) ( (x) < (y) ? (x) : (y) )
#endif

struct Screen *cloneTopScreen( LONG MoreColors, LONG GetPublic )
{
	LONG sMod, sDep, i, Wid, Hei, offx, offy;
	struct Screen *Scr, *nScr = 0L;
	struct Rectangle DispRect;
	struct DrawInfo *dri;
	UWORD *cols;
	BPTR lock;
	
	/* Lock IntuitionBase so nothing goes away while we're playing with it */
	lock = LockIBase( 0 );
	
	/* Grab the first screen and get its attributes */
	if( GetPublic )
		Scr = LockPubScreen( 0L );
	else
		Scr = IntuitionBase->FirstScreen;
	sMod = GetVPModeID(&( Scr->ViewPort )); /* Screen Mode ID */
	offx = Scr->LeftEdge; 
	offy = Scr->TopEdge;
	Wid = Scr->Width;
	Hei = Scr->Height;
	if( dri = GetScreenDrawInfo( Scr ))
		sDep = MoreColors ? dri->dri_Depth + 1 : dri->dri_Depth;
	if( cols = AllocMem( sizeof( WORD ) * ( 1L << sDep ), MEMF_CLEAR ))
		for( i = 0; i < ( 1L << dri->dri_Depth ); ++i )
			cols[i] = GetRGB4( Scr->ViewPort.ColorMap, i );
	
	if( GetPublic )
		UnlockPubScreen( 0L, Scr );

	UnlockIBase( lock );
	
	QueryOverscan( sMod, &DispRect, OSCAN_TEXT );

	Wid = min( Wid, DispRect.MaxX - DispRect.MinX + 1 );
	Hei = min( Hei, DispRect.MaxY - DispRect.MinY + 1 );
	
	if( sMod != INVALID_ID )
	{
		nScr = OpenScreenTags( NULL, SA_DisplayID, sMod, SA_Depth, sDep,
							  SA_Width, Wid, SA_Height, Hei, SA_Behind, TRUE,
							  SA_Quiet, TRUE, TAG_DONE );
		if( nScr )
		{
			BltBitMap( Scr->RastPort.BitMap, offx < 0 ? -offx : 0,
					  offy < 0 ? -offy : 0, nScr->RastPort.BitMap, 0, 0,
					  Wid, Hei, 0x00C0, 0x00FF, NULL );
			LoadRGB4( &(nScr->ViewPort), cols, 1L << sDep );
			if( offx > 0 )
				MoveScreen( nScr, offx, 0 );
			WaitBlit();
			ScreenToFront( nScr );
		}
	}

	if( cols )
		FreeMem( cols, ( 1L << sDep ) * sizeof( UWORD ));

	if( dri )
		FreeScreenDrawInfo( Scr, dri );

	return nScr;
}
#endif

#ifdef FADESCREEN

#include <exec/memory.h>
#include <graphics/displayinfo.h>

LONG fadeScreen39( struct Screen *Screen, LONG Del, LONG ModeID, LONG Pct )
{
	LONG NumCols = ( 1L << Screen->RastPort.BitMap->Depth ), RetVal = OK;
	struct DisplayInfo *Inf;
	ULONG *ColorTable;

	ColorTable = AllocVec( sizeof( LONG ) * ( 3 * NumCols + 2 ), MEMF_CLEAR );
	Inf = AllocVec( sizeof( struct DisplayInfo ), MEMF_CLEAR );
	
	if( ColorTable && Inf )
	{
		LONG i, n, Iters, MaxCols, BPG = 8;
		BPTR Dbg = Open( "RAM:Dbg.out", MODE_NEWFILE );
		
		if( GetDisplayInfoData( 0L, (UBYTE *)Inf, sizeof( struct DisplayInfo ),
							   DTAG_DISP, ModeID ))
			BPG = ( Inf->RedBits + Inf->GreenBits + Inf->BlueBits ) / 3;
		
		MaxCols = 1L << BPG;
		
		GetRGB32( Screen->ViewPort.ColorMap, 0, NumCols, ColorTable + 1 );
		ColorTable[0] = ( NumCols << 16L );
	
		Iters = Pct * MaxCols / 100;
		
		for( n = 0; n < Iters && RetVal == OK; ++n )
		{
			for( i = 0; i < 3 * NumCols; ++i )
			{
				if( ColorTable[i+1] > 1L << ( 32 - BPG ))
					ColorTable[i+1] -= ( 1L << ( 32 - BPG ));
				else
					ColorTable[i+1] = 0;
			}
			
			LoadRGB32(&( Screen->ViewPort ), ColorTable );
			
			for( i = 0; i < Del && RetVal == OK; ++i )
			{
				WaitTOF();
				if(!( i % 5 ))
					RetVal = ContinueBlanking();
			}
		}

		Close( Dbg );
	}
	else
		RetVal = FAILED;

	if( ColorTable )
		FreeVec( ColorTable );

	if( Inf )
		FreeVec( Inf );

	return RetVal;
}

LONG fadeScreen( struct Screen *Screen, ULONG delay, ULONG ModeID, ULONG Pct )
{
	LONG NumCols = ( 1L << Screen->RastPort.BitMap->Depth );
	LONG col, i, n, rv = OK;
	
	if( V39 )
		return fadeScreen39( Screen, delay, ModeID, Pct );
		
	for( n = 0; n < Pct * 16 / 100 && rv == OK; n++ )
	{
		for( i = 0; i < NumCols; ++i )
		{
			col = GetRGB4( Screen->ViewPort.ColorMap, i );
			SetRGB4(&( Screen->ViewPort ), i,
					(( col & 0x0F00 ) >> 8 ) > 0 ?
					(( col & 0x0F00 ) >> 8 ) - 1 : 0,
					(( col & 0x00F0 ) >> 4 ) > 0 ?
					(( col & 0x00F0 ) >> 4 ) - 1 : 0,
					( col & 0x000F ) > 0 ? ( col & 0x000F ) - 1 : 0 );
		}

		for( i = 0; i < delay && rv == OK; i++ )
		{
			WaitTOF();
			if(!( i % 5 ))
				rv = ContinueBlanking();
		}
	}

	return rv;
}
#endif

#ifdef BLANKMOUSE
struct Window *BlankWnd;
UWORD *BlankPtr;

VOID BlankMousePointer( struct Screen *Scr )
{
	ULONG   oldmodes;
	
	Forbid();
	oldmodes = SetPubScreenModes( 0 );
	if( BlankPtr = AllocVec( 3*2*sizeof( UWORD ) ,
							MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR )) {
		if( BlankWnd = OpenWindowTags( 0L, WA_Activate, TRUE, WA_Left, 0,
									  WA_Top, 0, WA_Width, 1, WA_Height, 1,
									  WA_Borderless, TRUE, WA_CustomScreen,
									  Scr, TAG_END )) {
			/* Set a pointer sprite of size 16*1 (alloc and clear data for
			   sprite def which is 2 control words, 2 words 4-color data for
			   each line and 2 empty words at the end (as suggested in
			   Hardware Ref. Manual)).
			   */
			SetPointer( BlankWnd, BlankPtr, 1, 16, 0, 0 );
		}
	}
	SetPubScreenModes( oldmodes );
	Permit();
}

VOID UnblankMousePointer( VOID )
{
	if( BlankWnd )
		CloseWindow( BlankWnd );
	if( BlankPtr )
		FreeVec( BlankPtr );
}
#endif

#ifdef RAINBOWPALETTE
#include <math.h>
#include <exec/execbase.h>
#ifndef ExecBase
#define ExecBase (*(( struct ExecBase ** )4L ))
#endif

struct ColorStruct {
	ULONG Red;
	ULONG Green;
	ULONG Blue;
};

#define CastAndShift( x ) ((( int )( x * Colors )) << Shift )

struct ColorStruct *NewColorTable( LONG Colors, LONG Dep, LONG Offset )
{
	struct ColorStruct *Table;
	float incr = 360.0 / Colors;
	float p2, p3, f, h;
	LONG i, Shift;
	USHORT ih;

	Table = AllocVec( 2 * ( Colors + Offset ) * sizeof( struct ColorStruct ), MEMF_CLEAR );

	if( Table )
	{
		Shift = 32 - Dep;
		for( i = Offset, h = 0.0; i < Colors + Offset; i++, h += incr )
		{
			ih = ( USHORT )( h / 60.0 );
			f = h / 60.0 - ih;
			p2 = 1 - f;
			p3 = f;
			switch( ih )
			{
			case 0:
				Table[i].Red = Colors << Shift;
				Table[i].Green = CastAndShift( p3 );
				Table[i].Blue = 0;
				break;
			case 1:
				Table[i].Red = CastAndShift( p2 );
				Table[i].Green = Colors << Shift;
				Table[i].Blue = 0;
				break;
			case 2:
				Table[i].Red = 0;
				Table[i].Green = Colors << Shift;
				Table[i].Blue = CastAndShift( p3 );
				break;
			case 3:
				Table[i].Red = 0;
				Table[i].Green = CastAndShift( p2 );
				Table[i].Blue = Colors << Shift;
				break;
			case 4:
				Table[i].Red = CastAndShift( p3 );
				Table[i].Green = 0;
				Table[i].Blue = Colors << Shift;
				break;
			case 5:
				Table[i].Red = Colors << Shift;
				Table[i].Green = 0;
				Table[i].Blue = CastAndShift( p2 );
				break;
			}
		}

		CopyMem(&( Table[Offset] ), &( Table[Colors+Offset] ),
				Colors * sizeof( struct ColorStruct ));
		
		return Table;
	}

	return 0L;
}

VOID agaInit( struct Screen *Screen, LONG Offset, LONG ExtendPal )
{
	static struct ColorStruct *Table = NULL;
	LONG Colors, PDep, PColors, Temp1, Temp2, Dep;
	static LONG ColorPos = 0;
	
	if( Screen )
	{
		Dep = Screen->BitMap.Depth;
		PDep = ( Dep < ( 9 - ExtendPal )) ? Dep + ExtendPal : 8;
		Colors = ( 1L << Dep ) - Offset;
		PColors = ( 1L << PDep ) - Offset;
		if( !Table )
		{
			Table = NewColorTable( PColors, PDep, Offset );
			if( Offset )
				SetRGB32(&(Screen->ViewPort), 0, 0, 0, 0 );
		}
		
		ColorPos = ( ++ColorPos % PColors );
		
		if( Table )
		{
			Temp1 = Table[ColorPos].Blue;
			Temp2 = Table[ColorPos+Colors+1].Red;
			
			Table[ColorPos].Blue = ( Colors << 16L ) + Offset;
			Table[ColorPos+Colors+1].Red = 0;
			
			LoadRGB32(&(Screen->ViewPort), &( Table[ColorPos].Blue ));
			
			Table[ColorPos].Blue = Temp1;
			Table[ColorPos+Colors+1].Red = Temp2;
		}
	}
	else
	{
		if( Table )
		{
			FreeVec( Table );
			Table = NULL;
		}
	}
}

VOID ecsInit( struct Screen *Screen )
{
	UWORD Table6[] = { 0, 0x0F20, 0x0E30, 0x0C50, 0x0B60, 0x0980, 0x0890,
						   0x06B0, 0x05C0, 0x03E0, 0x02F0, 0x00F2, 0x00E3,
						   0x00C5, 0x00B6, 0x0098, 0x006B, 0x005C, 0x003E,
						   0x002F, 0x020F, 0x030E, 0x050C, 0x060B, 0x0809,
						   0x0908, 0x0B06, 0x0C05, 0x0E03, 0x0F02, 0x0F00,
						   0x0F00, 0x0F00, 0x0F20, 0x0E30, 0x0C50, 0x0B60,
						   0x0980, 0x0890, 0x06B0, 0x05C0, 0x03E0, 0x02F0,
						   0x00F2, 0x00E3, 0x00C5, 0x00B6, 0x0098, 0x006B,
						   0x005C, 0x003E, 0x002F, 0x020F, 0x030E, 0x050C,
						   0x060B, 0x0809, 0x0908, 0x0B06, 0x0C05, 0x0E03,
						   0x0F02, 0x0F00, 0x0F20, 0x0E30, 0x0C50, 0x0B60,
						   0x0980, 0x0890, 0x06B0, 0x05C0, 0x03E0, 0x02F0,
						   0x00F2, 0x00E3, 0x00C5, 0x00B6, 0x0098, 0x006B,
						   0x005C, 0x003E, 0x002F, 0x020F, 0x030E, 0x050C,
						   0x060B, 0x0809, 0x0908, 0x0B06, 0x0C05, 0x0E03,
						   0x0F02, 0x0F00, 0x0F00, 0x0F00, 0x0F20, 0x0E30,
						   0x0C50, 0x0B60, 0x0980, 0x0890, 0x06B0, 0x05C0,
						   0x03E0, 0x02F0, 0x00F2, 0x00E3, 0x00C5, 0x00B6,
						   0x0098, 0x006B, 0x005C, 0x003E, 0x002F, 0x020F,
						   0x030E, 0x050C, 0x060B, 0x0809, 0x0908, 0x0B06,
						   0x0C05, 0x0E03, 0x0F02, 0x0F00 };
	UWORD Table5[] = { 0, 0x0F20, 0x0E30, 0x0C50, 0x0B60, 0x0980, 0x0890,
						   0x06B0, 0x05C0, 0x03E0, 0x02F0, 0x00F2, 0x00E3,
						   0x00C5, 0x00B6, 0x0098, 0x006B, 0x005C, 0x003E,
						   0x002F, 0x020F, 0x030E, 0x050C, 0x060B, 0x0809,
						   0x0908, 0x0B06, 0x0C05, 0x0E03, 0x0F02, 0x0F00,
						   0x0F00, 0x0F20, 0x0E30, 0x0C50, 0x0B60, 0x0980,
						   0x0890, 0x06B0, 0x05C0, 0x03E0, 0x02F0, 0x00F2,
						   0x00E3, 0x00C5, 0x00B6, 0x0098, 0x006B, 0x005C,
						   0x003E, 0x002F, 0x020F, 0x030E, 0x050C, 0x060B,
						   0x0809, 0x0908, 0x0B06, 0x0C05, 0x0E03, 0x0F02,
						   0x0F00, 0x0F00 };
	UWORD Table4[] = { 0, 0x0E03, 0x0B06, 0x0909, 0x060B, 0x030E, 0x003E,
						   0x006B, 0x0099, 0x00B6, 0x00E3, 0x03E0, 0x06B0,
						   0x0990, 0x0B60, 0x0E30, 0x0E03, 0x0B06, 0x0909,
						   0x060B, 0x030E, 0x003E, 0x006B, 0x0099, 0x00B6,
						   0x00E3, 0x03E0, 0x06B0, 0x0990, 0x0B60, 0x0E30 };
	UWORD Table3[] = { 0, 0x0E00, 0x0770, 0x00E0, 0x0077, 0x000E, 0x0707,
						   0x0707, 0x0E00, 0x0770, 0x00E0, 0x0077, 0x000E,
						   0x0707, 0x0707 };
	UWORD Table2[] = { 0, 0x0E00, 0x00E0, 0x000E, 0x0E00, 0x00E0, 0x000E };
	UWORD Table1[] = { 0, 0x0FFF };
	UWORD *Table[6], *Cols, Tmp;
	LONG Colors[] = { 2, 4, 8, 16, 32, 64 };
	static LONG i = 0;
	
	Table[0] = Table1; Table[1] = Table2; Table[2] = Table3; Table[3] = Table4;
	Table[4] = Table5; Table[5] = Table6;
	
	if( Screen ) {
		Cols = &( Table[Screen->BitMap.Depth-1][i] );
		Tmp = Cols[0];
		Cols[0] = 0;
		LoadRGB4(&( Screen->ViewPort ), Cols, Colors[Screen->BitMap.Depth-1] );
		Cols[0] = Tmp;
		i = ++i%( Colors[Screen->BitMap.Depth-1] );
	}
}

VOID RainbowPalette( struct Screen *Screen, LONG Offset, LONG ExtendPal )
{
	if( ExecBase->LibNode.lib_Version < 39 )
		ecsInit( Screen );
	else
		agaInit( Screen, Offset, ExtendPal );
}
#endif
