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

#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
struct BitMap *newMap;
#include <exec/execbase.h>
#define ExecBase (*(( struct ExecBase ** )4L ))

VOID FreeBitMap37( struct BitMap *bm, LONG Width, LONG Height )
{
	LONG i;
	
	if( ExecBase->LibNode.lib_Version < 39 ) {
		for( i = 0; i < bm->Depth; i++ )
			if( bm->Planes[i] )
				FreeRaster( bm->Planes[i], Width, Height );
		FreeVec( bm );
	} else
		FreeBitMap( bm );
}

struct BitMap *AllocBitMap37( ULONG Width, ULONG Height, ULONG Depth,
							 struct Screen *Scr )
{
	struct BitMap *bm;
	LONG  i;
	
	if( ExecBase->LibNode.lib_Version < 39 ) {
		if( bm = AllocVec( sizeof( struct BitMap ), MEMF_CLEAR|MEMF_PUBLIC )) {
			InitBitMap( bm, Depth, Width, Height );
			for( i = 0; i < Depth; i++ )
				if(!( bm->Planes[i] = AllocRaster( Width, Height )))
					break;
			if( i == Depth )
				return( bm );
			FreeBitMap37( bm, Width, Height );
			return( NULL );
		}
	} else
		return( AllocBitMap( Width, Height, Depth, BMF_DISPLAYABLE,
							   Scr->RastPort.BitMap ));
}

struct Screen *cloneTopScreen( LONG MoreColors )
{
	struct Screen *Scr, *nScr = 0L;
	struct DrawInfo *dri;
	BPTR lock;
	LONG sMod, sDep, i, Wid, Hei, offx, offy;
	UWORD *cols;
	
	/* Lock IntuitionBase so nothing goes away while we're playing with it */
	lock = LockIBase( 0 );
	
	/* Grab the first screen and get its attributes */
	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( newMap = AllocBitMap37( Wid, Hei, sDep, Scr ))
		BltBitMap( Scr->RastPort.BitMap, 0, 0, newMap, 0, 0, Wid, Hei, 0x00C0, 0x00FF, NULL );
	
	UnlockIBase( lock );
	
	if(( newMap )&&( sMod != INVALID_ID )) {
		if( nScr = OpenScreenTags( NULL, SA_Width, Wid, SA_Height, Hei,
								  SA_Depth, sDep, SA_Overscan, OSCAN_MAX,
								  SA_DisplayID, sMod, SA_Pens,
								  (ULONG)dri->dri_Pens, SA_Behind, TRUE,
								  SA_BitMap, (ULONG)newMap, SA_Quiet, TRUE )) {
			LoadRGB4( &(nScr->ViewPort), cols, 1L << sDep );
			MoveScreen( nScr, offx, offy<0?offy:0 );
			ScreenToFront( nScr );
		}
	}
	if( cols )
		FreeMem( cols, ( 1L << sDep ) * sizeof( UWORD ));
	if( dri )
		FreeScreenDrawInfo( Scr, dri );

	return( nScr );
}

void closeTopScreen( struct Screen *Scr )
{
	LONG Wid, Hei;
	
	Wid = Scr->Width;
	Hei = Scr->Height;
	CloseScreen( Scr );
	FreeBitMap37( newMap, Wid, Hei );
}
#endif

#ifdef FADESCREEN

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

LONG fadeScreen( struct Screen *Screen, ULONG delay, ULONG ModeID )
{
	LONG col, i, go, rv, NumCols = ( 1L << Screen->RastPort.BitMap->Depth );
	ULONG *ColorTable, *Color, BitsPerGun = 8;
	struct DisplayInfo *DspInf;
	
	if( ExecBase->LibNode.lib_Version > 38 )
	{
		ColorTable = AllocVec( sizeof( LONG ) * ( 3 * NumCols + 2 ), MEMF_CLEAR );
		if( !ColorTable )
			return FAILED;
		
		if( DspInf = AllocVec( sizeof( struct DisplayInfo ), MEMF_CLEAR ))
		{
			if( GetDisplayInfoData( 0L, ( UBYTE * )DspInf, sizeof( struct DisplayInfo ), DTAG_DISP,
								   ModeID ))
				BitsPerGun = ( DspInf->RedBits + DspInf->GreenBits + DspInf->BlueBits ) / 3;
			FreeVec( DspInf );
		}

		GetRGB32( Screen->ViewPort.ColorMap, 0, NumCols, ColorTable + 1 );
		ColorTable[0] = ( NumCols << 16L );
	}
	
	do
	{
		if( ExecBase->LibNode.lib_Version < 39 )
		{
			for( go = 0, i = 0; i < NumCols; ++i )
			{
				go = ( 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 );
			}
		}
		else
		{
			for( go = 0, i = 0, Color = ColorTable; i < 3 * NumCols; ++i )
			{
				if( *++Color )
				{
					go = 1;
					if( *Color > ( 1L << ( 32 - BitsPerGun )))
						*Color -= ( 1L << ( 32 - BitsPerGun ));
					else
						*Color = 0;
				}
			}
			LoadRGB32(&( Screen->ViewPort ), ColorTable );
		}
		for( i = 0; i < delay; i++ )
		{
			WaitTOF();
			if(!( i % 5 ))
			{
				rv = ContinueBlanking();
				if( rv != OK )
					return rv;
			}
		}
	}
	while( go );

	if( ExecBase->LibNode.lib_Version > 38 )
		FreeVec( ColorTable );

	return OK;
}
#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;
	LONG i, Shift;
	float incr = 360.0 / Colors;
	float p2, p3, f, h;
	USHORT ih;

	if( Table = AllocVec( 2 * ( Colors + Offset ) * sizeof( struct ColorStruct ), MEMF_CLEAR )) {
		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 Colors, Temp1, Temp2, Dep;
	static LONG ColorPos = 0;
	static struct ColorStruct *Table = NULL;
	
	if( Screen ) {
		Dep = Screen->BitMap.Depth;
		Colors = ( 1L << Dep ) - Offset;
		if( !Table ) {
			Table = NewColorTable( Colors, Dep, Offset );
			if( Offset )
				SetRGB32(&(Screen->ViewPort), 0, 0, 0, 0 );
		}
		
		ColorPos = ( ++ColorPos % Colors );
		
		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 ));
			Delay( 8 - Dep );
			
			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] );
		Delay(( LONG )( 8 - Screen->BitMap.Depth ));
	}
}

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