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

#include <exec/types.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <devices/timer.h>

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

#include <exec/memory.h>

#include "SH_view.h"
#include "SH_timer.h"

#include "/tools.h"


BOOL Cyber=FALSE;

__chip STATIC UWORD EmptyPointer[] =
{
	0, 0, 0, 0, 0
};

UBYTE *ChunkyAdr;
ULONG tmpPalette[256*3+2];
LONG dPalette[256*3];

VOID __asm CGFX_C2P_FI(REGISTER __a0 DVIEW *DView)
{
 (void)WritePixelArray(DView->Chunky,0,0,
                       DView->Width,
                       DView->DisplayRP,
                       0,0,
                       DView->Width,
                       DView->Height,
                       RECTFMT_LUT8);
}

DVIEW *OpenView(ULONG Width, ULONG Height, ULONG Depth, ULONG ModeID,
								ULONG *Palette, ULONG Flags)
{
DVIEW *DView;
ULONG Interleaved;
ULONG Left, Top;

if(Cyber)
{
  if((ModeID = BestCModeIDTags(
                              CYBRBIDTG_Depth,Depth,
                              CYBRBIDTG_NominalWidth,320,
                              CYBRBIDTG_NominalHeight,200,
                              TAG_DONE
                                 )) == INVALID_ID) return FALSE;

}

	if(Flags & DVF_CENTER)
	{
    Height = 256;
		Left = 0;
		Top = 0;
	}
	else
	{
		Left = 0;
		Top = 0;
	}

	if((DView = AllocVec(sizeof(DVIEW),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
		return NULL;

	DView->Width = Width;
	DView->Height = Height;
	DView->Depth = Depth;
	DView->ModeID = ModeID;
	DView->Flags = Flags;

	if(Flags & DVF_INTERLEAVED)
		Interleaved = BMF_INTERLEAVED;
	else
		Interleaved = 0;

  if((DView->BitMap[0] = AllocBitMap(Width, Height, Depth,
                                     BMF_CLEAR | BMF_DISPLAYABLE | Interleaved,
                                     NULL)) == NULL)
	{
		CloseView(DView);
    return NULL;
	}

	if(Interleaved)
	  if(!(GetBitMapAttr(DView->BitMap[0], BMA_FLAGS) & BMF_INTERLEAVED))
  	{
	    CloseView(DView);
  	  return NULL;
	  }

	if(Flags & DVF_DBUFF)
	{
	  if((DView->BitMap[1] = AllocBitMap(Width, Height, Depth,
  	                                   BMF_CLEAR | BMF_DISPLAYABLE | Interleaved,
    	                                 NULL)) == NULL)
		{
			CloseView(DView);
    	return NULL;
		}

		if(Interleaved)
		  if(!(GetBitMapAttr(DView->BitMap[1], BMA_FLAGS) & BMF_INTERLEAVED))
  		{
	    	CloseView(DView);
	  	  return NULL;
		  }
	}

  if((DView->Screen = OpenScreenTags(NULL, SA_Left, Left,
                                           SA_Top, Top,
                                           SA_Width, Width,
                                           SA_Height, Height,
                                           SA_Depth, Depth,
                                           SA_BitMap, DView->BitMap[0],
                                           SA_ShowTitle, FALSE,
 								   SA_Quiet, TRUE,
                                           SA_Type, CUSTOMSCREEN,
                                           SA_DisplayID, ModeID,
                                           SA_Overscan, OSCAN_STANDARD,
                                           SA_AutoScroll, FALSE,
                                           SA_Draggable, FALSE,
                                           SA_Colors32, Palette,
                                           SA_Interleaved, Interleaved,
                                           SA_VideoControl, NULL,
                                           SA_MinimizeISG, TRUE,
                                           TAG_DONE)) == NULL)
  {
    CloseView(DView);
    return NULL;
  }

	DView->VP = &DView->Screen->ViewPort;

	if(Flags & DVF_DBUFF)
	{
	  if((DView->ScreenBuffer[0] = AllocScreenBuffer(DView->Screen,
  	                                               DView->BitMap[0],
    	                                             0)) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

  	if((DView->ScreenBuffer[1] = AllocScreenBuffer(DView->Screen,
	                                                 DView->BitMap[1],
	         	                                       0)) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

	  if((DView->RP[0] = AllocVec(sizeof(struct RastPort),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

	  InitRastPort(DView->RP[0]);
	  DView->RP[0]->BitMap = DView->BitMap[0];

	  if((DView->RP[1] = AllocVec(sizeof(struct RastPort),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

  	InitRastPort(DView->RP[1]);
	  DView->RP[1]->BitMap = DView->BitMap[1];

	  if((DView->SafePort[0] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->SafePort[1] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->DisplayPort[0] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->DisplayPort[1] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  DView->ScreenBuffer[0]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = DView->SafePort[0];
  	DView->ScreenBuffer[0]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = DView->DisplayPort[0];
	  DView->ScreenBuffer[1]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = DView->SafePort[1];
  	DView->ScreenBuffer[1]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = DView->DisplayPort[1];

	  ChangeScreenBuffer(DView->Screen, DView->ScreenBuffer[0]);

	  DView->Display = 0L;
  	DView->Render = 1L;

	  DView->DisplayRP = DView->RP[0];
  	DView->RenderRP = DView->RP[1];
	}
	else
	{
		DView->RP[0] = &DView->Screen->RastPort;

	  DView->Display = 0L;
  	DView->Render = 0L;

	  DView->DisplayRP = DView->RP[0];
  	DView->RenderRP = DView->RP[0];
	}

	if((DView->Window = OpenWindowTags(NULL, WA_Left, 0,
									 WA_Top, 0,
									 WA_Width, Width,
     								 WA_Height, Height,
									 WA_CustomScreen, DView->Screen,
	     							 WA_Backdrop, TRUE,
		     						 WA_Borderless, TRUE,
									 WA_NoCareRefresh, TRUE,
			     					 WA_Activate, FALSE,
									 WA_RMBTrap, TRUE,
     								 TAG_DONE)) == NULL)
	{
   	CloseView(DView);
    return NULL;
	}

	DView->WindowRP = DView->Window->RPort;

     ActivateWindow(DView->Window);
	SetPointer(DView->Window, EmptyPointer, 1, 1, 0, 0);

	if(Flags & DVF_CHUNKY)
	{
	  if((ChunkyAdr = AllocVec(Width*Height,MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

		DView->Chunky = ChunkyAdr;
          if(Cyber)
           {
		  DView->C2P = CGFX_C2P_FI;
           }
          else
           {
		  DView->C2P = C2P_FI;
           }
	}
	return DView;
}


VOID CloseView(DVIEW *DView)
{

	if(DView->Window)
	{
		CloseWindow(DView->Window);
	}

	if(DView->Flags & DVF_CHUNKY)
		if(DView->Chunky != NULL)
		{
			FreeVec(DView->Chunky);
		}

	if(DView->Flags & DVF_DBUFF)
	{
		SafeRender(DView);
	  WaitBlit();
  	while(!GetMsg(DView->DisplayPort[DView->Display]))
    	Wait(1L<<(DView->DisplayPort[DView->Display]->mp_SigBit));

	  if(DView->DisplayPort[1])
		{
	  	while(GetMsg(DView->DisplayPort[1]));

  	  DeleteMsgPort(DView->DisplayPort[1]);
		}

	  if(DView->DisplayPort[0])
		{
	  	while(GetMsg(DView->DisplayPort[0]));

  	  DeleteMsgPort(DView->DisplayPort[0]);
		}

	  if(DView->SafePort[1])
		{
	  	while(GetMsg(DView->SafePort[1]));

  	  DeleteMsgPort(DView->SafePort[1]);
		}

	  if(DView->SafePort[0])
		{
	  	while(GetMsg(DView->SafePort[0]));

  	  DeleteMsgPort(DView->SafePort[0]);
		}

	  if(DView->ScreenBuffer[1])
  	  FreeScreenBuffer(DView->Screen, DView->ScreenBuffer[1]);

	  if(DView->ScreenBuffer[0])
  	  FreeScreenBuffer(DView->Screen, DView->ScreenBuffer[0]);
	}

  if(DView->Screen)
    CloseScreen(DView->Screen);

	if(DView->Flags & DVF_DBUFF)
	{
	  if(DView->RP[1])
  	  FreeVec(DView->RP[1]);

	  if(DView->RP[0])
  	  FreeVec(DView->RP[0]);

		WaitBlit();

	  if(DView->BitMap[1])
  	  FreeBitMap(DView->BitMap[1]);
	}

	WaitBlit();

  if(DView->BitMap[0])
 	  FreeBitMap(DView->BitMap[0]);

  FreeVec(DView);
}


VOID ClearChunky(DVIEW *DView)
{
   ClearChunky320x200(DView);
}


VOID SwitchView(DVIEW *DView)
{

if(!Cyber)
{
	if(DView->Flags & DVF_DBUFF)
	{
	  WaitBlit();

  	while(!GetMsg(DView->DisplayPort[DView->Display]))
    	Wait(1L<<(DView->DisplayPort[DView->Display]->mp_SigBit));

	  DView->Display ^= 1L;
  	DView->Render ^= 1L;

	  DView->DisplayRP = DView->RP[DView->Display];
  	DView->RenderRP = DView->RP[DView->Render];

	  ChangeScreenBuffer(DView->Screen, DView->ScreenBuffer[DView->Display]);
	}
}
}


VOID SafeRender(DVIEW *DView)
{
if(!Cyber)
{
	if(DView->Flags & DVF_DBUFF)
	  while(!GetMsg(DView->SafePort[DView->Display]))
  	  Wait(1L<<(DView->SafePort[DView->Display]->mp_SigBit));
}
}


VOID FadeInPalette(DVIEW *DView, ULONG *Palette,
									 ULONG r, ULONG g, ULONG b, LONG Time)
{
ULONG ColorsNumber;
LONG tmpTime;
LONG i;

	ColorsNumber = Palette[0]>>16;
	tmpPalette[0] = Palette[0];
	for(i=0; i<ColorsNumber; i++)
	{
		tmpPalette[i*3+1] = r;
		tmpPalette[i*3+2] = g;
		tmpPalette[i*3+3] = b;
	}
	tmpPalette[ColorsNumber*3+1] = 0L;

	FadeInSupport1(dPalette, Palette, r, g, b, Time);

	WaitTOF();
	LoadRGB32(DView->VP, tmpPalette);

	XEvent();

	do
	{
		tmpTime = GetCurrentXTime();
		if(tmpTime > Time)
			tmpTime = Time;

		FadeInSupport2(dPalette, tmpPalette, r, g, b, tmpTime);

		WaitTOF();
		LoadRGB32(DView->VP, tmpPalette);
	}
	while(tmpTime < Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette);
}


VOID FadeOutPalette(DVIEW *DView, ULONG *Palette,
									 ULONG r, ULONG g, ULONG b, LONG Time)
{
ULONG ColorsNumber;
LONG tmpTime;
LONG i;

	ColorsNumber = Palette[0]>>16;
	tmpPalette[0] = Palette[0];
	tmpPalette[ColorsNumber*3+1] = 0L;

	FadeOutSupport1(dPalette, Palette, r, g, b, Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette);

	XEvent();

	do
	{
		tmpTime = GetCurrentXTime();
		if(tmpTime > Time)
			tmpTime = Time;

		FadeOutSupport2(dPalette, tmpPalette, Palette, tmpTime);

		WaitTOF();
		LoadRGB32(DView->VP, tmpPalette);
	}
	while(tmpTime < Time);

	for(i=0; i<ColorsNumber; i++)
	{
		tmpPalette[i*3+1] = r;
		tmpPalette[i*3+2] = g;
		tmpPalette[i*3+3] = b;
	}
	WaitTOF();
	LoadRGB32(DView->VP, tmpPalette);
}
