#include <proto/all.h>
#include <opal/opallib.h>
#include <graphics/gfxbase.h>
#include <exec/memory.h>


/* Typical interface to OpalVision from a rendering package
 */


/* Define this flag if you want to open a Virtual screen if
 * chip ram is running low.
 */

#define OPENVIRTUAL	1

/* Define this flag if you cannot set the LSB of bit of
 * the background colour.
 */

#define AUTOSYNC	1

	/* external functions */

BOOL Open_OpalScreen (ULONG Modes);
void Render_To_Opal (long Y, long Width, long Lines,
			UBYTE *Red, UBYTE *Green, UBYTE *Blue, BOOL Chunky);
void Opal_Render_Finished (void);
void Close_Opal (void);



extern struct GfxBase *GfxBase;
static struct OpalBase *OpalBase;
static struct OpalScreen *OScrn,*VScrn;
static long LastUpdateY,UpdateLines;


/*   Open the Opalvision screen. Modes must be any combination of
 * HIRES24,ILACE24,OVERSCAN24 as defined in Opallib.h.
 *   The screen will be opened in chip ram if possible. If there
 * is not enough chip ram, a virtual screen will be opened.
 */


BOOL Open_OpalScreen (ULONG Modes)
{
   long ImageSize;
   long Width,Height;

	if (OpalBase==NULL)
		OpalBase = (struct OpalBase *)OpenLibrary ("opal.library",0);
	if (OpalBase==NULL) return (FALSE);

		/* Calculate the amount of memory required for the screen */

	if (GfxBase->DisplayFlags & NTSC)
		{ if (Modes & OVERSCAN24)
			{ if (Modes & ILACE24)
				Height = 476;
			  else
				Height = 238;
			}
		  else
			{ if (Modes & ILACE24)
				Height = 400;
			  else
				Height = 200;
			}
		}
	 else
		{ if (Modes & OVERSCAN24)
			{ if (Modes & ILACE24)
				Height = 576;
			  else
				Height = 286;
			}
		  else
			{ if (Modes & ILACE24)
				Height = 512;
			  else
				Height = 256;
			}
		}


	if (Modes & OVERSCAN24)
		{ if (Modes & HIRES24)
			Width = 736L;
		  else
			Width = 368L;
		}
	else
		{ if (Modes & HIRES24)
			Width = 640L;
		  else
			Width = 320L;
		}

	if (Modes & PLANES8)
		ImageSize = Width*Height;
	else if (Modes & PLANES15)
		ImageSize = Width*Height*2L;
	else
		ImageSize = Width*Height*3L;

#ifdef OPENVIRTUAL

	if (AvailMem (MEMF_CHIP)<ImageSize)
		{ VScrn = CreateScreen24 (Modes,Width,Height);
		  if (VScrn==NULL) return (FALSE);
		  LastUpdateY = 0;
		  if (Modes & ILACE24)
			UpdateLines = 32;
		  else
			UpdateLines = 16;
		}
	else
#endif
		{ OScrn = OpenScreen24 (Modes);
		  if (OScrn==NULL) return (FALSE);
#ifdef AUTOSYNC
		  AutoSync24 (TRUE);
		  UpdateDelay24 (0);
#else
		  UpdateDelay24 (10);
#endif
		}
	return (TRUE);
}

/* Render image RGB data to the OpalVision FrameBuffer.
 *
 * Inputs:
 *	Y 		= Staring Y-position (line) to place data.
 *	Width 		= Width of the RGB data.
 *	Lines 		= Number of scan lines to render.
 *	Red,Green,Blue	= Pointers to Red, Green and Blue byte planes.
 *	Chunky		= Set to TRUE if RGB data is in chunky (interleaved)
 *			  format.
 */


void Render_To_Opal (long Y, long Width, long Lines,
			UBYTE *Red, UBYTE *Green, UBYTE *Blue, BOOL Chunky)
{
   UBYTE *RGBPlanes[3];
   struct OpalScreen *WriteScreen;

	RGBPlanes[0] = Red;
	RGBPlanes[1] = Green;
	RGBPlanes[2] = Blue;
	if (VScrn)
		WriteScreen = VScrn;
	else
		WriteScreen = OScrn;
	if (WriteScreen==NULL) return;
	if (Chunky)
		RGBtoOV (WriteScreen,RGBPlanes,0,Y,3*Width,Lines);
	else
		RGBtoOV (WriteScreen,RGBPlanes,0,Y,Width,Lines);
	if (VScrn)
		{ if ((LastUpdateY/UpdateLines) != (Y/UpdateLines))
			{ OScrn = LowMemUpdate24 (VScrn,0);
			  LastUpdateY = Y;
			}
		}
}

void Opal_Render_Finished (void)
{
	if (VScrn)
		OScrn = LowMemUpdate24 (VScrn,0);
}
	

void Close_Opal (void)
{
	if (OScrn)
		CloseScreen24();
	if (VScrn)
		FreeScreen24 (VScrn);
	if (OpalBase) CloseLibrary ((struct Library *)OpalBase);
	OScrn = NULL;
	VScrn = NULL;
	OpalBase = NULL;
}
