;/*
sc ignore=73 debug=line Zoom!.c
slink from lib:c.o Zoom!.o to Zoom! LIB LIB:sc.lib LIB:amiga.lib SC SD ND NOICONS
delete Zoom!.o
quit

*/

#include <exec/memory.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <3AM/libraries/bitmap.h>
#include <stdio.h>
#include <string.h>

#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <3AM/clib/bitmap_protos.h>
#include <3AM/pragmas/bitmap_pragmas.h>

UWORD chip Lens_data[] = {
0x0000, 0x0000, 0x0000, 0x0700, 0x0700, 0x1FC0, 0x18C0, 0x37E0, 0x3060, 0x68B0, 0x2020, 0x5070,
0x4010, 0xA038, 0x4010, 0xA038, 0x4010, 0xA038, 0x2020, 0x5050, 0x3060, 0x48B0,
0x18F0, 0x2718, 0x0738, 0x18CC, 0x001C, 0x0726, 0x000E, 0x0013, 0x0004, 0x000E,
0x0000, 0x0004, 0x0000, 0x0000 };

UWORD chip SPlus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x7F3F,0xC000,0x7F3F,0xC000,0x7807,0xC000,0x7F3F,0xC000,
0x7F3F,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xFE1F,0x8000,
0xFEDF,0x8000,0xF0C3,0x8000,0xF7FB,0x8000,0xF0C3,0x8000,0xFEDF,0x8000,0xFE1F,0x8000,
0xFFFF,0x8000,0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 };

UWORD chip SMinus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7807,0xC000,0x7FFF,0xC000,
0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xFFFF,0x8000,
0xFFFF,0x8000,0xF003,0x8000,0xF7FB,0x8000,0xF003,0x8000,0xFFFF,0x8000,0xFFFF,0x8000,
0xFFFF,0x8000,0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 };

UWORD chip SAutoPlus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x767F,0xC000,0x66FF,0xC000,0x67E7,0xC000,0x7081,0xC000,
0x7FE7,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xF07F,0x8000,
0xEFBF,0x8000,0xDFC3,0x8000,0xDF18,0x8000,0xEF7E,0x8000,0xF018,0x8000,0xFFC3,0x8000,
0xFFFF,0x8000,0x8000,0x0000 };

UWORD chip SAutoMinus_data[] = {
0x7FFF,0xC000,0x7FFF,0xC000,0x767F,0xC000,0x66FF,0xC000,0x67BF,0xC000,0x70FF,0xC000,
0x7F81,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0x7FFF,0xC000,0xFFFF,0x8000,0xF07F,0x8000,
0xEFBF,0x8000,0xDFDF,0x8000,0xDFDF,0x8000,0xEF00,0x8000,0xF07E,0x8000,0xFF00,0x8000,
0xFFFF,0x8000,0x8000,0x0000 };

struct Image SPlus_image = { 0,0,18,10,3,SPlus_data,7,0,0 };
struct Image SMinus_image = { 0,0,18,10,3,SMinus_data,7,0,0 };
struct Image SAutoPlus_image = { 0,0,18,10,2,SAutoPlus_data,3,0,0 };
struct Image SAutoMinus_image = { 0,0,18,10,2,SAutoMinus_data,3,0,0 };

#define ZOOM_IN_GDG_ID	1
#define ZOOM_OUT_GDG_ID	2
#define AUTO_PLUS_GDG_ID 3
#define AUTO_MINUS_GDG_ID 4

struct Gadget ZoomInGdg = {
	NULL, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SPlus_image, NULL, NULL, 0L, NULL, ZOOM_IN_GDG_ID, NULL };

struct Gadget ZoomOutGdg = {
	&ZoomInGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SMinus_image, NULL, NULL, 0L, NULL, ZOOM_OUT_GDG_ID, NULL };

struct Gadget AutoPlusGdg = {
	&ZoomOutGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SAutoPlus_image, NULL, NULL, 0L, NULL, AUTO_PLUS_GDG_ID, NULL };

struct Gadget AutoMinusGdg = {
	&AutoPlusGdg, -17, 0, 18, 10, GFLG_RELRIGHT | GFLG_GADGHCOMP | GFLG_GADGIMAGE,
	GACT_RELVERIFY | GACT_RIGHTBORDER, GTYP_BOOLGADGET, &SAutoMinus_image, NULL, NULL, 0L, NULL, AUTO_MINUS_GDG_ID, NULL };

struct NewWindow nwt = {
	60, 60, 142, 75, 0, 0, IDCMP_CLOSEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_GADGETUP | IDCMP_NEWSIZE,
	WFLG_ACTIVATE | WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_RMBTRAP,
	&AutoMinusGdg, NULL, NULL, NULL, NULL, 120, 61, 0, 0, WBENCHSCREEN };

#define PROGRAM_NAME "Zoom! v1.3"
#define AUTHORS_NAME "Stefano Reksten"

char *SCR_NAME = PROGRAM_NAME" © 1993 by "AUTHORS_NAME;
char *WND_NAME = PROGRAM_NAME" - S:00 - A:00";

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *BitMapBase, *IconBase;
struct Window *window;

struct BitMap *bm, *intermediateBm, *originalBm;
struct MsgPort *TimerMP;
struct timerequest *TimerIO;
ULONG time_delay;
BOOL timer_running = FALSE;

UWORD height, width, lastX, lastY;
UBYTE depth, scaling_factor = 2;


void FreeBitMaps( void )
{
if ( originalBm )
	DisposeBitMap( originalBm );
if ( intermediateBm )
	DisposeBitMap( intermediateBm );
if ( bm )
	DisposeBitMap( bm );
}


BOOL AllocBitMaps( void )
{
register UWORD w, h;

width = ( window->Width - window->BorderLeft - window->BorderRight ) / scaling_factor;
height = ( window->Height - window->BorderTop - window->BorderBottom ) / scaling_factor;

w = (width +1) * scaling_factor;
h = (height +1) * scaling_factor;

bm = CreateBitMap( w, h, depth );
intermediateBm = CreateBitMap( w, (height+1), depth );
originalBm = CreateBitMap( (width+1), (height+1), depth );

if ( bm && intermediateBm && originalBm )
	return( TRUE );
else
	{
	FreeBitMaps();
	return( FALSE );
	}
}


void Zoom( void )
{
register UWORD X = lastX;
register UWORD Y = lastY;

UWORD w = width * scaling_factor / 2;
UWORD h = height * scaling_factor / 2;

UWORD sw = window->WScreen->Width;
UWORD sh = window->WScreen->Height;

register UWORD xCoord, yCoord, cycle, srvCoord, srvCoord2;

if ( X > w/scaling_factor )
	X -= w/scaling_factor;
else	X = 0;

if ( X > sw - width )
	X = sw - width;

if ( Y > h/scaling_factor )
	Y -= h/scaling_factor;
else	Y = 0;

if ( Y > sh - height )
	Y = sh - height;

BltBitMap( window->WScreen->RastPort.BitMap, X, Y,
	   originalBm, 0, 0,
	   width, height, 0xC0, 0xFF, NULL );

srvCoord = 0;
for ( xCoord = 0; xCoord < width; xCoord++ )
	{
	for ( cycle = 0; cycle < scaling_factor; cycle++ )
		{
		BltBitMap(
			originalBm, xCoord, 0,
			intermediateBm, srvCoord, 0,
			1, height, 0xC0, 0xFF, NULL );
		srvCoord++;
		}
	}

srvCoord = RASSIZE( (width+1)*scaling_factor, (height+1)*scaling_factor );
for ( cycle = 0; cycle < bm->Depth; cycle++ )
	BltClear( bm->Planes[cycle], srvCoord, 1 );

srvCoord = 0;
srvCoord2 = width * scaling_factor;
for ( yCoord = 0; yCoord < height; yCoord++ )
	for ( cycle = 0; cycle < scaling_factor; cycle++ )
		{
		BltBitMap(
			intermediateBm, 0, yCoord,
			bm, 0, srvCoord,
			srvCoord2, 1, 0xC0, 0xFF, NULL );
		srvCoord++;
		}

WaitTOF();
BltBitMapRastPort( bm, 0, 0, window->RPort, window->BorderLeft, window->BorderTop, window->Width - window->BorderLeft - window->BorderRight, window->Height - window->BorderTop - window->BorderBottom, 0xC0 );
}


BOOL SetUpTimer( void )
{
if ( TimerMP = CreateMsgPort() )
	{
	if ( TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof( struct timerequest ) ) )
		{
		if ( !(OpenDevice( "timer.device", UNIT_VBLANK, (struct IORequest *)TimerIO, 0 ) ) )
			{
			TimerIO->tr_node.io_Command = TR_ADDREQUEST;
			TimerIO->tr_time.tv_secs = time_delay;
			SendIO( (struct IORequest *)TimerIO );
			return( TRUE );
			}
		DeleteExtIO( (struct IORequest *)TimerIO );
		}
	DeleteMsgPort( TimerMP );
	}
return( FALSE );
}


void RemoveTimer( void )
{
if ( TimerIO )
	{
	if ( !( CheckIO( (struct IORequest *)TimerIO ) ) )
		AbortIO( (struct IORequest *)TimerIO );
	WaitIO( (struct IORequest *)TimerIO );
	CloseDevice( (struct IORequest *)TimerIO );
	DeleteExtIO( (struct IORequest *)TimerIO );
	DeletePort( TimerMP );
	TimerIO = NULL;
	}
}


void SetTitles( void )
{
WND_NAME[15] = '0' + scaling_factor / 10;
WND_NAME[16] = '0' + scaling_factor % 10;

if ( !time_delay )
	{
	WND_NAME[22] = 'N';
	WND_NAME[23] = 'A';
	}
else
	{
	if ( time_delay < 100 )
		{
		WND_NAME[22] = '0' + time_delay / 10;
		WND_NAME[23] = '0' + time_delay % 10;
		}
	else
		{
		WND_NAME[22] = '?';
		WND_NAME[23] = '!';
		}
	}

SetWindowTitles( window, WND_NAME, SCR_NAME );
}

void ProcessMessages( void )
{
register BOOL stay = TRUE;
register ULONG signal, mask = 1L<<window->UserPort->mp_SigBit | SIGBREAKF_CTRL_C;
register struct IntuiMessage *msg;
register struct Message *timerMsg;
register struct Gadget *gdg;
register ULONG class;
register UWORD code;

while( stay )
	{
	if ( timer_running )
		mask |= 1L<<TimerMP->mp_SigBit;

	signal = Wait ( mask );

	if ( signal & SIGBREAKF_CTRL_C )
		stay = FALSE;

	if ( timer_running && signal & 1L<<TimerMP->mp_SigBit )
		{
		if ( timerMsg = GetMsg( TimerMP ) )
			{
			Zoom();
			TimerIO->tr_node.io_Command = TR_ADDREQUEST;
			TimerIO->tr_time.tv_secs = time_delay;
			SendIO( (struct IORequest *)TimerIO );
			}
		}

	if ( signal & 1L<<window->UserPort->mp_SigBit )
		{
		while ( msg = (struct IntuiMessage *)GetMsg( window->UserPort ) )
			{
			class = msg->Class;
			code = msg->Code;

			switch( class )
				{
				case IDCMP_CLOSEWINDOW:
					stay = FALSE;
					break;
				case IDCMP_NEWSIZE:
					FreeBitMaps();
					width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
					height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
					if ( stay = AllocBitMaps() )
						Zoom();
					break;
				case IDCMP_MOUSEBUTTONS:
					switch( code )
						{
						case MENUUP:
							lastX = IntuitionBase->MouseX;
							lastY = IntuitionBase->MouseY;
							if ( !( window->WScreen->ViewPort.Modes & LACE ) )
								lastY >>= 1;
							if ( (window->WScreen->ViewPort.Modes & SUPERHIRES ) )
								lastX <<= 1;
							else
							if ( !(window->WScreen->ViewPort.Modes & HIRES ) )
								lastX >>= 1;
 							Zoom();
							break;
						default:
							break;
						}
					break;
				case IDCMP_GADGETUP:
					gdg = (struct Gadget *)msg->IAddress;
					if ( gdg->GadgetID == ZOOM_IN_GDG_ID && scaling_factor < 40 )
						{
						FreeBitMaps();
						scaling_factor++;
						width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
						height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
						if ( stay = AllocBitMaps() )
							Zoom();
						}
					else
					if ( gdg->GadgetID == ZOOM_OUT_GDG_ID && scaling_factor > 2 )
						{
						FreeBitMaps();
						scaling_factor--;
						width = ( window->Width - window->BorderLeft - window->BorderRight -1 ) / scaling_factor;
						height = ( window->Height - window->BorderTop - window->BorderBottom -1 ) / scaling_factor;
						if ( stay = AllocBitMaps() )
							Zoom();
						}
					else
					if ( gdg->GadgetID == AUTO_PLUS_GDG_ID )
						{
						time_delay++;
						if ( timer_running == FALSE )
							{
							if ( timer_running = SetUpTimer() )
								OnGadget( &AutoMinusGdg, window, NULL );
							}
						}
					else
					if ( gdg->GadgetID == AUTO_MINUS_GDG_ID )
						{
						if ( time_delay && timer_running )
							{
							time_delay--;
							RemoveTimer();
							if ( !time_delay )
								{
								timer_running = FALSE;
								OffGadget( &AutoMinusGdg, window, NULL );
								}
							else	SetUpTimer();
							}
						}
					SetTitles();
					break;
				default:
					break;
				}
			ReplyMsg( (struct Message *)msg );
			}
		}
	}
}


void main( int argc, char *argv[] )
{
if ( argc )
	{
	LONG args[6];
	struct RDArgs *rdargs;

	memset( args, 0, 24 );
	if ( rdargs = ReadArgs( "Auto/N,Scale/N,Left/N,Top/N,Width/N,Height/N", args, NULL ) )
		{
		if ( args[0] ) { time_delay = *((ULONG *)args[0]); timer_running = TRUE; }
		if ( args[1] ) scaling_factor = *((ULONG *)args[1]);
		if ( args[2] ) nwt.LeftEdge = *((ULONG *)args[2]);
		if ( args[3] ) nwt.TopEdge = *((ULONG *)args[3]);
		if ( args[4] ) nwt.Width = *((ULONG *)args[4]);
		if ( args[5] ) nwt.Height = *((ULONG *)args[5]);
		FreeArgs( rdargs );
		}
	}
else
if ( IconBase = OpenLibrary( "icon.library", 0L ) )
	{
	char **ttypes = ArgArrayInit( argc, argv );

	if ( time_delay = ArgInt( ttypes, "AUTO", 0 ) )
		timer_running = TRUE;
	scaling_factor = ArgInt( ttypes, "SCALE", 2 );
	if ( scaling_factor < 2 || scaling_factor > 40 )
		scaling_factor = 2;
	nwt.LeftEdge = ArgInt( ttypes, "LEFT", 60 );
	nwt.TopEdge = ArgInt( ttypes, "TOP", 60 );
	nwt.Width = ArgInt( ttypes, "WIDTH", 142 );
	nwt.Height = ArgInt( ttypes, "HEIGHT", 75 );

	ArgArrayDone();
	CloseLibrary( IconBase );
	}

if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 0L ) )
		{
		if ( BitMapBase = OpenLibrary( "bitmap.library", 0L ) )
			{
			depth = IntuitionBase->ActiveScreen->BitMap.Depth;

			ZoomInGdg.TopEdge = IntuitionBase->ActiveScreen->Font->ta_YSize + 3;
			ZoomOutGdg.TopEdge = ZoomInGdg.TopEdge + 10;
			AutoPlusGdg.TopEdge = ZoomOutGdg.TopEdge + 10;
			AutoMinusGdg.TopEdge = AutoPlusGdg.TopEdge + 10;

			nwt.MaxWidth = IntuitionBase->ActiveScreen->Width;
			nwt.MaxHeight = IntuitionBase->ActiveScreen->Height;

			if ( window = OpenWindow( &nwt ) )
				{
				SetTitles();
				SetAPen( window->RPort, 0 );
				SetPointer( window, Lens_data, 16L, 16L, -6, -6 );
				if ( AllocBitMaps() )
					{
					if ( timer_running )
						timer_running = SetUpTimer();
					if ( !timer_running || !time_delay )
						OffGadget( &AutoMinusGdg, window, NULL );
					lastX = 0;
					lastY = 0;
					Zoom();
					ProcessMessages();
					FreeBitMaps();
					if ( timer_running )
						RemoveTimer();
					}
				ClearPointer( window );
				CloseWindow( window );
				}
			CloseLibrary( BitMapBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
