/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by MXM
 *
 *	Name .....: Port2.c
 *	Created ..: Thursday 02-Aug-90 13:59
 *	Revision .: 0
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	02-Aug-90       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

	/* Included header files. */

#define __NO_PRAGMAS 1

#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <devices/inputevent.h>
#include <devices/gameport.h>
#include <graphics/gfxbase.h>
#include <graphics/sprite.h>
#include <devices/input.h>
#include <exec/memory.h>
#include <functions.h>

	/* Global symbols. */

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct Window		*Window;
struct MsgPort		*GamePort;
struct IOStdReq		*GameReq;
struct MsgPort		*InputPort;
struct IOStdReq		*InputReq;
struct InputEvent	*InputEvent;
struct SimpleSprite	 PointerSprite;
USHORT 			*PointerImage;
struct Preferences	*Preferences;
BYTE			 ControllerType = GPCT_NOCONTROLLER;

	/* Signal bits. */

#define SIG_GAMEPORT	(1 << GamePort -> mp_SigBit)
#define SIG_WINDOW	(1 << Window -> UserPort -> mp_SigBit)

	/* Delta movement values we wish to be signalled. */

#define XMOVE 1
#define YMOVE 1

	/* Window title and width of the window. */

#define NAME "Port2"
#define WIDTH (84 + (sizeof(NAME) - 1) * 8)

	/* New window structure. */

struct NewWindow NewWindow =
{
	0,11,
	WIDTH,10,
	0,1,
	CLOSEWINDOW,
	RMBTRAP | WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH,
	(struct Gadget *)NULL,
	(struct Image *)NULL,
	(STRPTR)NAME,
	(struct Screen *)NULL,
	(struct BitMap *)NULL,
	0,0,
	0,0,
	WBENCHSCREEN
};

	/* A GameTrigger structure. */

struct GamePortTrigger GameTrigger =
{
	GPTF_UPKEYS|GPTF_DOWNKEYS,	/* Key events. */
	~0,				/* Event timeout (very large). */
	XMOVE,				/* Movement. */
	YMOVE
};

	/* Stub routines. */

VOID _cli_parse(){}
VOID _wb_parse(){}
LONG Chk_Abort(VOID) { return(0); }

	/* CloseAll(BYTE ExitCode):
	 *
	 *	Close all resources and exit.
	 */

VOID
CloseAll(BYTE ExitCode)
{
		/* If we have allocated a controller, release the
		 * port.
		 */

	if(ControllerType == GPCT_MOUSE)
	{
		ControllerType = GPCT_NOCONTROLLER;

		GameReq -> io_Command	= GPD_SETCTYPE;
		GameReq -> io_Length	= 1;
		GameReq -> io_Flags	= IOF_QUICK;
		GameReq -> io_Data	= (APTR)&ControllerType;

		DoIO(GameReq);
	}

		/* Release the sprite. */

	if(PointerSprite . num != -1)
		FreeSprite(PointerSprite . num);

	if(Window)
		CloseWindow(Window);

	if(InputEvent)
		FreeMem(InputEvent,sizeof(struct InputEvent));

	if(PointerImage)
		FreeMem(PointerImage,POINTERSIZE * sizeof(USHORT));

	if(Preferences)
		FreeMem(Preferences,sizeof(struct Preferences));

	if(GameReq)
	{
		if(GameReq -> io_Device)
		{
			GameReq -> io_Command = CMD_CLEAR;
			DoIO(GameReq);

			CloseDevice(GameReq);
		}

		DeleteStdIO(GameReq);
	}

	if(GamePort)
		DeletePort(GamePort);

	if(InputReq)
	{
		if(InputReq -> io_Device)
			CloseDevice(InputReq);

		DeleteStdIO(InputReq);
	}

	if(InputPort)
		DeletePort(InputPort);

	if(GfxBase)
		CloseLibrary(GfxBase);

	if(IntuitionBase)
		CloseLibrary(IntuitionBase);

	exit(ExitCode);
}

	/* OpenAll():
	 *
	 *	Open all the required resources.
	 */

VOID
OpenAll()
{
	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
		CloseAll(RETURN_FAIL + 0);

	if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
		CloseAll(RETURN_FAIL + 1);

	if(!(GamePort = (struct MsgPort *)CreatePort(NULL,0)))
		CloseAll(RETURN_FAIL + 2);

	if(!(GameReq = (struct IOStdReq *)CreateStdIO(GamePort)))
		CloseAll(RETURN_FAIL + 3);

	if(OpenDevice("gameport.device",1,GameReq,0))
		CloseAll(RETURN_FAIL + 4);

	if(!(InputPort = (struct MsgPort *)CreatePort(NULL,0)))
		CloseAll(RETURN_FAIL + 5);

	if(!(InputReq = (struct IOStdReq *)CreateStdIO(InputPort)))
		CloseAll(RETURN_FAIL + 6);

	if(OpenDevice("input.device",0,InputReq,0))
		CloseAll(RETURN_FAIL + 7);

	if(!(Preferences = (struct Preferences *)AllocMem(sizeof(struct Preferences),MEMF_PUBLIC | MEMF_CLEAR)))
		CloseAll(RETURN_FAIL + 8);

	if(!(PointerImage = (USHORT *)AllocMem(POINTERSIZE * sizeof(USHORT),MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR)))
		CloseAll(RETURN_FAIL + 9);

	if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_PUBLIC | MEMF_CLEAR)))
		CloseAll(RETURN_FAIL + 10);

	if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
		CloseAll(RETURN_FAIL + 11);

		/* Get the current system preferences. */

	GetPrefs(Preferences,sizeof(struct Preferences));

		/* Copy pointer image to user buffer. */

	CopyMem(Preferences -> PointerMatrix,PointerImage,POINTERSIZE * sizeof(USHORT));

		/* Set up the sprite control structure. */

	PointerSprite . posctldata	= PointerImage;
	PointerSprite . height		= 16;

		/* Allocate a hardware sprite. */

	if((PointerSprite . num = GetSprite(&PointerSprite,1)) == -1)
		CloseAll(RETURN_FAIL + 12);

		/* Check if we are able to allocate the second controller
		 * port.
		 */

	GameReq -> io_Command	= GPD_ASKCTYPE;
	GameReq -> io_Length	= 1;
	GameReq -> io_Flags	= IOF_QUICK;
	GameReq -> io_Data	= (APTR)&ControllerType;

	Forbid();

	DoIO(GameReq);

		/* The port is already allocated. */

	if(ControllerType != GPCT_NOCONTROLLER)
	{
		Permit();
		CloseAll(RETURN_FAIL + 13);
	}

		/* Install a mouse type controller. */

	ControllerType = GPCT_MOUSE;

	GameReq -> io_Command	= GPD_SETCTYPE;
	GameReq -> io_Length	= 1;
	GameReq -> io_Flags	= IOF_QUICK;
	GameReq -> io_Data	= (APTR)&ControllerType;

	DoIO(GameReq);

	Permit();

		/* Start queueing. */

	GameReq -> io_Command	= GPD_SETTRIGGER;
	GameReq -> io_Length	= sizeof(struct GamePortTrigger);
	GameReq -> io_Data	= (APTR)&GameTrigger;

	DoIO(GameReq);

		/* Initialize IORequests. */

	GameReq -> io_Command	= GPD_READEVENT;
	GameReq -> io_Length	= sizeof(struct InputEvent);
	GameReq -> io_Data	= (APTR)InputEvent;

	InputReq -> io_Command	= IND_WRITEEVENT;
	InputReq -> io_Length	= sizeof(struct InputEvent);
	InputReq -> io_Data	= (APTR)InputEvent;
}

	/* main():
	 *
	 *	The main program. 
	 */

VOID
main()
{
	LONG	PointerX = 0,PointerY = 0;
	ULONG	SignalSet;

	OpenAll();

		/* Read the first controller event. */

	SendIO(GameReq);

	FOREVER
	{
		SignalSet = Wait(SIG_GAMEPORT | SIG_WINDOW);

			/* Close the window? */

		if(SignalSet & SIG_WINDOW)
			CloseAll(RETURN_OK);

			/* Remove queued messages. */

		while(GetMsg(GamePort));

			/* Mouse move event. */

		if(InputEvent -> ie_X || InputEvent -> ie_Y)
		{
				/* Calculate delta values. */

			PointerX += InputEvent -> ie_X * 2;
			PointerY += InputEvent -> ie_Y * 2;

				/* Avoid view limits. */

			if(PointerX < 0)
				PointerX = 0;

			if(PointerY < 0)
				PointerY = 0;

			if(PointerX > 639)
				PointerX = 639;

			if(PointerY > 511)
				PointerY = 511;

				/* Move second mouse pointer. */

			MoveSprite(NULL,&PointerSprite,(PointerX >> 1) + Preferences -> XOffset,(PointerY >> 1) + Preferences -> YOffset);
		}

			/* Hit a mouse button, move the real mouse pointer
			 * to the current sprite position.
			 */

		if(InputEvent -> ie_Code != IECODE_NOBUTTON)
		{
			InputEvent -> ie_Qualifier	&= ~IEQUALIFIER_RELATIVEMOUSE;

			InputEvent -> ie_Class		 = IECLASS_POINTERPOS;
			InputEvent -> ie_X		 = PointerX;
			InputEvent -> ie_Y		 = PointerY;

			DoIO(InputReq);
		}

			/* Read the next event. */

		SendIO(GameReq);
	}
}
