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

#include <exec/types.h>
#include <devices/timer.h>
#include <proto/graphics.h>

#include "/Shared/EE_view.h"
#include "/Shared/EE_timer.h"
#include "/Renderer/EM_structures.h"
#include "TN_animation.h"


IMPORT LONG dPalette[256*3];
IMPORT ULONG tmpPalette[256*3+2];
ULONG *origPalette;
LONG FadeFlag;

LONG LogoPosX, LogoPosY;
DOUBLE LogoCPosX, LogoCPosY;
DOUBLE LogoDPosX, LogoDPosY;
DOUBLE LogoEPosX, LogoEPosY;


LONG TN_DoAnim(DVIEW *DView, SCENE *Scene, ANIM_COMMAND *AnimList,
							 LONG (*RenderFrame)(DVIEW *DView, SCENE *Scene))
{
CAMERA *Camera;
ANIM_CAMERA AnimCamera;
LONG State;
ANIM_COMMAND *CurrentAnimCommand;
DOUBLE Time2Go, AnimTime, OverfillTime;
BOOL next_seq;

	Camera = Scene->Camera;

	CurrentAnimCommand = AnimList;

	Time2Go = 0;
	AnimTime = 0;
	OverfillTime = 0;

	AnimCamera.cPosX = AnimCamera.ePosX = Camera->PosX;
	AnimCamera.cPosY = AnimCamera.ePosY = Camera->PosY;
	AnimCamera.cPosZ = AnimCamera.ePosZ = Camera->PosZ;
	AnimCamera.cRotX = AnimCamera.eRotX = Camera->RotX;
	AnimCamera.cRotY = AnimCamera.eRotY = Camera->RotY;
	AnimCamera.cRotZ = AnimCamera.eRotZ = Camera->RotZ;

	for(;;)
	{
		State = TN_InterpreteAnimList(&CurrentAnimCommand, &AnimCamera, &Time2Go);

		XEvent();

		if(State != IAL_OK)
			return State;

		next_seq = FALSE;

		do
		{
			AnimTime = (DOUBLE)GetCurrentXTime() + OverfillTime;

			if(AnimTime < Time2Go)
			{
				switch(FadeFlag)
				{
					case FADE_FROM_BLACK:
//						WaitTOF();
						LoadRGB32(DView->VP, tmpPalette);
						FadeInSupport2(dPalette, tmpPalette, 0L, 0L, 0L, (LONG)AnimTime);
						break;

					case FADE_TO_BLACK:
//						WaitTOF();
						LoadRGB32(DView->VP, tmpPalette);
						FadeOutSupport2(dPalette, tmpPalette, origPalette, (LONG)AnimTime);
						break;
				}

				Camera->PosX = (LONG)(AnimCamera.cPosX + AnimCamera.dPosX * AnimTime);
				Camera->PosY = (LONG)(AnimCamera.cPosY + AnimCamera.dPosY * AnimTime);
				Camera->PosZ = (LONG)(AnimCamera.cPosZ + AnimCamera.dPosZ * AnimTime);
				Camera->RotX = (LONG)(AnimCamera.cRotX + AnimCamera.dRotX * AnimTime);
				Camera->RotY = (LONG)(AnimCamera.cRotY + AnimCamera.dRotY * AnimTime);
				Camera->RotZ = (LONG)(AnimCamera.cRotZ + AnimCamera.dRotZ * AnimTime);

				Camera->RotX %= ANGLES_NUMBER;
				while(Camera->RotX < 0)
					Camera->RotX += ANGLES_NUMBER;

				Camera->RotY %= ANGLES_NUMBER;
				while(Camera->RotY < 0)
					Camera->RotY += ANGLES_NUMBER;

				Camera->RotZ %= ANGLES_NUMBER;
				while(Camera->RotZ < 0)
					Camera->RotZ += ANGLES_NUMBER;

				LogoPosX = (LONG)(LogoCPosX + LogoDPosX * AnimTime);
				LogoPosY = (LONG)(LogoCPosY + LogoDPosY * AnimTime);

				State = RenderFrame(DView, Scene);

				if(State != IAL_OK)
					return State;
			}
			else
			{
				switch(FadeFlag)
				{
					case FADE_FROM_BLACK:
//						WaitTOF();
						LoadRGB32(DView->VP, origPalette);
						break;

					case FADE_TO_BLACK:
						memset(&tmpPalette[1], 0, ((tmpPalette[0]>>16)*3+1)*4);
//						WaitTOF();
						LoadRGB32(DView->VP, tmpPalette);
						break;
				}

				Camera->PosX = (LONG)(AnimCamera.cPosX = AnimCamera.ePosX);
				Camera->PosY = (LONG)(AnimCamera.cPosY = AnimCamera.ePosY);
				Camera->PosZ = (LONG)(AnimCamera.cPosZ = AnimCamera.ePosZ);
				Camera->RotX = (LONG)(AnimCamera.cRotX = AnimCamera.eRotX);
				Camera->RotY = (LONG)(AnimCamera.cRotY = AnimCamera.eRotY);
				Camera->RotZ = (LONG)(AnimCamera.cRotZ = AnimCamera.eRotZ);

				Camera->RotX %= ANGLES_NUMBER;
				while(Camera->RotX < 0)
					Camera->RotX += ANGLES_NUMBER;

				Camera->RotY %= ANGLES_NUMBER;
				while(Camera->RotY < 0)
					Camera->RotY += ANGLES_NUMBER;

				Camera->RotZ %= ANGLES_NUMBER;
				while(Camera->RotZ < 0)
					Camera->RotZ += ANGLES_NUMBER;

				LogoPosX = (LONG)(LogoCPosX = LogoEPosX);
				LogoPosY = (LONG)(LogoCPosY = LogoEPosY);

				OverfillTime = AnimTime - Time2Go;
				next_seq = TRUE;
			}
		}
		while(!next_seq);
	}
}


LONG TN_InterpreteAnimList(ANIM_COMMAND **AnimCommand, ANIM_CAMERA *AnimCamera,
													 DOUBLE *Time2Go)
{
DOUBLE Time;

	AnimCamera->dPosX = 0;
	AnimCamera->dPosY = 0;
	AnimCamera->dPosZ = 0;
	AnimCamera->dRotX = 0;
	AnimCamera->dRotY = 0;
	AnimCamera->dRotZ = 0;

	FadeFlag = NO_FADE;

	LogoDPosX = 0;
	LogoDPosY = 0;

	for(;;)
	{
		switch((*AnimCommand)->Command)
		{
			case AC_MOVEX:
				AnimCamera->ePosX = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosX = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cPosX;
				break;

			case AC_MOVEY:
				AnimCamera->ePosY = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosY = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cPosY;
				break;

			case AC_MOVEZ:
				AnimCamera->ePosZ = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosZ = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cPosZ;
				break;

			case AC_RMOVEX:
				AnimCamera->ePosX += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_RMOVEY:
				AnimCamera->ePosY += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_RMOVEZ:
				AnimCamera->ePosZ += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dPosZ = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_ROTATIONX:
				AnimCamera->eRotX = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotX = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cRotX;
				break;

			case AC_ROTATIONY:
				AnimCamera->eRotY = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotY = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cRotY;
				break;

			case AC_ROTATIONZ:
				AnimCamera->eRotZ = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotZ = (DOUBLE)((*AnimCommand)->Parameter) -
														AnimCamera->cRotZ;
				break;

			case AC_RROTATIONX:
				AnimCamera->eRotX += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_RROTATIONY:
				AnimCamera->eRotY += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_RROTATIONZ:
				AnimCamera->eRotZ += (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->dRotZ = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETPOSX:
				AnimCamera->ePosX = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cPosX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETPOSY:
				AnimCamera->ePosY = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cPosY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETPOSZ:
				AnimCamera->ePosZ = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cPosZ = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETROTX:
				AnimCamera->eRotX = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cRotX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETROTY:
				AnimCamera->eRotY = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cRotY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_SETROTZ:
				AnimCamera->eRotZ = (DOUBLE)((*AnimCommand)->Parameter);
				AnimCamera->cRotZ = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_LMOVEX:
				LogoEPosX = (DOUBLE)((*AnimCommand)->Parameter);
				LogoDPosX = (DOUBLE)((*AnimCommand)->Parameter) - LogoCPosX;
				break;

			case AC_LMOVEY:
				LogoEPosY = (DOUBLE)((*AnimCommand)->Parameter);
				LogoDPosY = (DOUBLE)((*AnimCommand)->Parameter) - LogoCPosY;
				break;

			case AC_LRMOVEX:
				LogoEPosX += (DOUBLE)((*AnimCommand)->Parameter);
				LogoDPosX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_LRMOVEY:
				LogoEPosY += (DOUBLE)((*AnimCommand)->Parameter);
				LogoDPosY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_LSETPOSX:
				LogoEPosX = (DOUBLE)((*AnimCommand)->Parameter);
				LogoCPosX = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_LSETPOSY:
				LogoEPosY = (DOUBLE)((*AnimCommand)->Parameter);
				LogoCPosY = (DOUBLE)((*AnimCommand)->Parameter);
				break;

			case AC_FADE_FROM_BLACK:
				origPalette = (ULONG *)((*AnimCommand)->Parameter);
				tmpPalette[0] = origPalette[0];
				memset(&tmpPalette[1], 0, ((tmpPalette[0]>>16)*3+1)*4);
				FadeFlag = FADE_FROM_BLACK;
				break;

			case AC_FADE_TO_BLACK:
				origPalette = (ULONG *)((*AnimCommand)->Parameter);
				memcpy(tmpPalette, origPalette, ((origPalette[0]>>16)*3+2)*4);
				FadeFlag = FADE_TO_BLACK;
				break;

			case AC_DO:
				Time = (DOUBLE)((*AnimCommand)->Parameter);

				AnimCamera->dPosX /= Time;
				AnimCamera->dPosY /= Time;
				AnimCamera->dPosZ /= Time;
				AnimCamera->dRotX /= Time;
				AnimCamera->dRotY /= Time;
				AnimCamera->dRotZ /= Time;

				LogoDPosX /= Time;
				LogoDPosY /= Time;

				switch(FadeFlag)
				{
					case FADE_FROM_BLACK:
						FadeInSupport1(dPalette, origPalette, 0L, 0L, 0L, (LONG)Time);
						break;

					case FADE_TO_BLACK:
						FadeOutSupport1(dPalette, origPalette, 0L, 0L, 0L, (LONG)Time);
						break;

				}

				*Time2Go = (ULONG)Time;
				(*AnimCommand)++;
				return IAL_OK;

			case AC_QUIT:
				return DA_NORMAL_TERMINATION;

			default:
				return DA_ILLEGAL_COMMAND;
		}

		(*AnimCommand)++;
	}
}
