
/* this source implements aMiPEG's interface to CyberGraphX */


#include <string.h>
#include <stdlib.h>

#include <exec/exec.h>
#include <cybergraphics/cybergraphics.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <dos/dos.h>

#include <cybergraphics/cgxvideo.h>
#include <pragmas/cgxvideo_pragmas.h>
#include <clib/cgxvideo_protos.h>

#include <proto/graphics.h>
#include <proto/exec.h>
#include <proto/cybergraphics.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/asyncio.h>

#include "video.h"
#include "proto.h"

extern int doneFlag;
extern int fullFlag;
extern int ditherType;
extern int cyber_pub;
extern struct GfxBase *GfxBase;

struct Library *CyberGfxBase;
struct Library *CGXVideoBase;

ULONG cyber_mode;
ULONG depth;
struct Screen *cyber_screen;
struct Window *cyber_window;
int original_x, original_y;
VLayerHandle VLH;


static void Quit(char *why, int failcode)
{
	puts(why);
	exit(failcode);
}

static void output_term(void)
{
	close_timer();

	if(input)
	{
		CloseAsync(input);
		input = NULL;
	}

	if(VLH)
	{
		DetachVLayer(VLH);
		DeleteVLayerHandle(VLH);
	}

	if(cyber_window)
		CloseWindow(cyber_window);

	if(!cyber_pub && cyber_screen)
		CloseScreen(cyber_screen);

	if(CGXVideoBase)
		CloseLibrary(CGXVideoBase);

	if (GfxBase) CloseLibrary((struct Library *)GfxBase);
	if (CyberGfxBase) CloseLibrary(CyberGfxBase);
	if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase);
}

void DrawCyberGfxImage(UWORD *data, int x, int y)
{
	int win_x, win_y, i;

	if(ditherType == CYBERGFXVLAYER_DITHER || ditherType == CYBERGFXVLAYERGRAY_DITHER)
	{
		if(LockVLayer(VLH))
		{
			UWORD *address = (UWORD *)GetVLayerAttr(VLH, VOA_BaseAddress);

			for(i = 0; i < y; i++)
			{
				memcpy(address, data, x << 1);
				address += x;
				data += ((x + 15) >> 4) << 4;
			}

			UnlockVLayer(VLH);

			return;
		}
	}

	win_x = cyber_window->Width - cyber_window->BorderLeft - cyber_window->BorderRight;
	win_y = cyber_window->Height - cyber_window->BorderTop - cyber_window->BorderBottom;

	if(win_x == x && win_y == y)
	{
		if(ditherType == CYBERGFXGRAY_DITHER)
			WritePixelArray(data, 0, 0, x & 0x0f ? ((x >> 4) + 1 ) << 4 : x, cyber_window->RPort, cyber_window->BorderLeft, cyber_window->BorderTop, x, y, RECTFMT_GREY8);
		else
			WritePixelArray(data, 0, 0, (x & 0x0f ? ((x >> 4) + 1 ) << 4 : x ) * 4, cyber_window->RPort, cyber_window->BorderLeft, cyber_window->BorderTop, x, y, RECTFMT_ARGB);
	}
	else
	{
		if(ditherType == CYBERGFXGRAY_DITHER)
			ScalePixelArray(data, x, y, x & 0x0f ? ((x >> 4) + 1 ) << 4 : x, cyber_window->RPort, cyber_window->BorderLeft, cyber_window->BorderTop, win_x, win_y, RECTFMT_GREY8);
		else
			ScalePixelArray(data, x, y, (x & 0x0f ? ((x >> 4) + 1 ) << 4 : x) * 4, cyber_window->RPort, cyber_window->BorderLeft, cyber_window->BorderTop, win_x, win_y, RECTFMT_ARGB);
	}
}

int handle_window(void)
{
	struct IntuiMessage *imsg;
	struct IntuiMessage msg;
	static ULONG last_secs, last_micros;

	if(ditherType == PIV_DITHER)
	{
		return (p96_handle_window());
	}
	if(cyber_window)
	{
		while(imsg = (struct IntuiMessage *)GetMsg(cyber_window->UserPort))
		{
			CopyMem((char *)imsg, (char *)&msg, (long)sizeof(struct IntuiMessage));
			ReplyMsg((struct Message *)imsg);
			switch(msg.Class)
			{
				case IDCMP_VANILLAKEY:
					if(msg.Code == '\x1b' || msg.Code == 'q')
                    {
											doneFlag = DONE_REALLY;
											return(FALSE);
                    }
                    if(msg.Code == 13 || msg.Code == 32)    /* space & return */
                        return(FALSE);
                    break;

				case IDCMP_CLOSEWINDOW:
				{
					doneFlag = DONE_NOT_REALLY;
					return(FALSE);
				}

				case IDCMP_MOUSEBUTTONS:
					if(!fullFlag && msg.Code == SELECTDOWN)
					{
						if(DoubleClick(last_secs, last_micros, msg.Seconds, msg.Micros))
							ChangeWindowBox(cyber_window, cyber_window->LeftEdge, cyber_window->TopEdge, original_x, original_y);

						last_secs = msg.Seconds;
						last_micros = msg.Micros;
					}
				break;

				default:
				break;
			}
		}
	}
	return(TRUE);
}


BOOL init_cybergfx(void)
{
	if(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37))
		if(CyberGfxBase = OpenLibrary("cybergraphics.library", 40))
			if(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39))
				if(ditherType == CYBERGFXVLAYER_DITHER || ditherType == CYBERGFXVLAYERGRAY_DITHER)
				{
					if(CGXVideoBase = OpenLibrary("cgxvideo.library", 41))
						return(TRUE);
				}
				else
					return(TRUE);
			else
				Quit("graphics.library v39+ not present", 25);
		else
			Quit("cybergraphics.library v40+ not present", 25);
	else
		Quit("intuition.library is too old, <V39", 25);
}

int get_cyber_mode(void)
{
	return((int)CModeRequestTags(NULL,
													CYBRMREQ_WinTitle, "Select a screenmode for MPEG window",
													CYBRMREQ_MinDepth, 15,
													TAG_DONE));
}


unsigned long InitCyberGfxDisplay(unsigned long modeid)
{
	UWORD pens[] = { ~0 };

	atexit(output_term);

	if(init_cybergfx())
	{
		if(cyber_pub || (modeid != 0xffffffff) || (modeid = get_cyber_mode()) != 0xffffffff)
		{
			if(cyber_pub)
			{
				cyber_screen = LockPubScreen(pubname_ptr);
				modeid = GetVPModeID(&cyber_screen->ViewPort);
				ScreenToFront(cyber_screen);
				UnlockPubScreen(NULL, cyber_screen);
			}

			cyber_mode = modeid;
			depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, cyber_mode);
			if(depth < 15 && ditherType != CYBERGFXVLAYER_DITHER && ditherType != CYBERGFXVLAYERGRAY_DITHER)
				Quit("aMiPEG: this screen is not deep enough (needed at least 15 bits).", 25);

			if(cyber_screen || (cyber_screen = OpenScreenTags(NULL,
							SA_Width, STDSCREENWIDTH,
							SA_Height, STDSCREENHEIGHT,
							SA_DisplayID, cyber_mode,
							SA_Title, (UBYTE *)"aMiPEG 1.0 by Michael Rausch and Miloslaw Smyk",
							SA_Pens, &pens,
							SA_SysFont, 1,
							SA_Depth, depth,
							TAG_DONE)))
			{


				if(cyber_window = OpenWindowTags(NULL,
									cyber_pub ? WA_PubScreenName : WA_CustomScreen, cyber_pub ? pubname_ptr : cyber_screen,
									WA_Flags, WFLG_ACTIVATE | (fullFlag ? WFLG_BORDERLESS : WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_SIZEGADGET | WFLG_SIZEBBOTTOM),
                	WA_IDCMP, CLOSEWINDOW | MOUSEBUTTONS | VANILLAKEY,
                	(fullFlag ? TAG_SKIP : TAG_IGNORE), 8,
	                WA_InnerWidth, 160,
  	              WA_InnerHeight,120,
  	              WA_MaxWidth, ~0,
  	              WA_MaxHeight, ~0,
  	              WA_MinWidth, 60,
  	              WA_MinHeight, 60,
    	            WA_Title, "Playing MPEG animation",
    	            WA_ScreenTitle, (UBYTE *)"aMiPEG 1.0 by Michael Rausch and Miloslaw Smyk",
      	          TAG_DONE))

					return(modeid);
			}
		}
	}
	Quit("aMiPEG: unable to open screen/window...", 25);
}
