/*****************************************************************************
  Name :     Siberian 
  Author:	 Carlos Sarria
  Date :     July 1998
  Platform : Dreamcast Set5 (CLX2.2 + SH4)
 
  Description : Punchtrough demo.

  Copyright : 1998 by VideoLogic Limited. All rights reserved.
******************************************************************************/
#include <math.h>

#include "KMTools.h"
#include "KMShell.h"

#define PUNCHTHROUGH 1

/* 3D data */
#include "Siberian.h"

/* Textures have been loaded with Data.c */
extern const unsigned char Snow[];
extern const unsigned char VideoL[];
extern const unsigned char Pine4[];
extern const unsigned char Pine[];
extern const unsigned char branch2[];
extern const unsigned char Bush[];
extern const unsigned char Bark[];
extern const unsigned char Back[];


/*************************************************/
/*	Globals                                      */
/*************************************************/

KMSURFACEDESC		Tex[256];				/* texture surface */
KMVERTEXCONTEXT		VertexContext[256];		/* Vertex context */
KMVERTEX_03			*KmVert[256];			/* Vertex pointers*/

/* SET4 / SET5 memory start*/ 
int MemPtr = 0x0c400000;

int ScreenWidth=640, ScreenHeight=480;

km_vector CameraFrom		= { 0.0f, 0.0f, -100.0f};
km_vector CameraTo			= { 0.0f, 0.0f, 100.0f};
km_vector LightDirection	= {1.0f, -1.0f, 1.0f};

unsigned nFrame = 0;
unsigned nTrees = 170;
unsigned Type	= 0;
unsigned Cont	= 0;
unsigned nPT	= 0;
unsigned bStart = FALSE;
float	 Ang    = 0;
float    Distance = 0;


/**************************************************/
/* Prototypes                                     */
/**************************************************/

void	InitMeshes			(void);
void	InitMaterials		(void);
void	RenderObject		(MATRIX *Matrx,  int Object);

/************************************************************************/
/* KMShell functions:                                                   */
/*    InitApplication                                                 */
/*    QuitApplication                                                 */
/*    RenderScene                                                     */
/*    PadControl                                                      * 
/*                                                                      */
/* WARNING : These functions must be created always because are called  */
/*           by KMShell.											    */
/************************************************************************/
/*----------------------------------------------------------------------*
 *  Function Name   :  InitApplication                              
 *  Inputs          :  None                                               
 *  Outputs         :  None                                                 
 *  Returns         :                                              
 *  Globals Used    :                                                
 *  Description     :   KMShellInitApplication() is called by KMShell to enable
 *						user to initialise the application                                           
 *----------------------------------------------------------------------*/
void InitApplication (void)
{

	KMShellSetVideo	(FALSE		/* Trans PreSort   */
					 );


	if (PUNCHTHROUGH)
	{
		KMShellSetBuffers (	40, 	/* % Opaque        */
							 0,	    /* % ModVol Opaque */
							 5,		/* % Translucent   */
							 0,		/* % ModVol Trans  */
							55);	/* % Punchthrough  */
	}
	else
	{
		KMShellSetBuffers (35, 		/* % Opaque        */
							0,		/* % ModVol Opaque */
						   60,		/* % Translucent   */
							0,		/* % ModVol Trans  */
							5);		/* % Punchthrough  */
	}
		

	KMABCTableInit (TRUE);

	InitMaterials ();

	InitMeshes();
}
/*----------------------------------------------------------------------*
 *  Function Name   :  QuitApplication                                 
 *  Inputs          :  None                                               
 *  Outputs         :  None                                                 
 *  Returns         :                                            
 *  Globals Used    :                                                 
 *  Description     :                                                  
 *----------------------------------------------------------------------*/
void QuitApplication (void)
{
	KMABCTableRelease();

	/* FREE TEXTURES */
	kmFreeTexture(&Tex[M_SNOW]);
	kmFreeTexture(&Tex[20]);
	kmFreeTexture(&Tex[M_B1_BARK]);
	kmFreeTexture(&Tex[M_B1_TRANS]);
	kmFreeTexture(&Tex[M_B2_TRUNK]);
	kmFreeTexture(&Tex[M_B2_TRANS]);
	kmFreeTexture(&Tex[M_B3_TRUNK]);
	kmFreeTexture(&Tex[M_B3_TRANS]);
	kmFreeTexture(&Tex[M_B4_BARK]);
	kmFreeTexture(&Tex[M_B4_TRANS]);
}

/*----------------------------------------------------------------------*
 *  Function Name   :  RenderScene                                      
 *  Inputs          :  None                                               
 *  Outputs         :  None                                                 
 *  Returns         :  FALSE to finish                                               
 *  Globals Used    :  nFrame, CameraTo, CameraFrom, nPT                                                
 *  Description     :  Draws everything in the scene.                                                 
 *----------------------------------------------------------------------*/
int RenderScene (void)
{
MATRIX			Matrx;
int				j;
unsigned		TreeCont = 21, BiCont=0;
float			Radius;
static unsigned	PathCont = 0;


	if (bStart == FALSE)
	{
		Ang += PI/80.0f;
		Distance += PI/60.0f;
	}

	Radius = 500 + 350 * sin ((double)Distance);

	CameraFrom[0] = cos(Ang) * Radius;
	CameraFrom[1] = 400;
	CameraFrom[2] = sin(Ang) * Radius;

	CameraTo[0] = *(Mesh[M_LOGO].pVertex+0);/*cos(Ang) * Radius/2.0f;*/
	CameraTo[1] = *(Mesh[M_LOGO].pVertex+1);/*20.0f;*/
	CameraTo[2] = *(Mesh[M_LOGO].pVertex+2);/*cos(Ang) * Radius/2.0f;*/

	
	/* Drawing the background */
	KMShellBackground (&VertexContext[20]);

	/* Drawing the trees (there are 4 different models) */
	for (j=0; j<nTrees; j++)
	{
      KMMatrixReset(&Matrx);

	  /* Reads one of the ground vertices and places a tree there */
	  KMMatrixTranslate (&Matrx,	*(Mesh[M_SNOW].pVertex+TreeCont*3+0), 
								*(Mesh[M_SNOW].pVertex+TreeCont*3+1)+50, 
								*(Mesh[M_SNOW].pVertex+3*TreeCont+2)
						);

	  TreeCont+=8;
	 
	  if(j%4==0) Type = (BiCont++&1)?2:0;
	  if(j%4==1) Type = 1;
	  if(j%4 >1) Type = 2;
	 
      switch (Type)
	  {
		case 0:
		nPT = PUNCHTHROUGH * 100;
		RenderObject (&Matrx, M_B2_TRANS);
		nPT = 0;
		RenderObject (&Matrx, M_B2_TRUNK);
		break;

		case 1:
		nPT = PUNCHTHROUGH * 100;
		RenderObject (&Matrx, M_B1_TRANS);
		nPT = 0;
		RenderObject (&Matrx, M_B1_BARK);
		break;


		case 2:
		nPT = PUNCHTHROUGH * 100;
		RenderObject (&Matrx, M_B4_TRANS);
		nPT = 0;
		RenderObject (&Matrx, M_B4_BARK);
		break;

	
		}
	}

   /* Drawing the ground */
   KMMatrixReset(&Matrx);
   RenderObject (&Matrx, M_SNOW);

   /* Drawing the logo */
   KMMatrixReset(&Matrx);
   RenderObject (&Matrx, M_LOGO);

   if(PUNCHTHROUGH) KMABCTablePrint3D (20.0f, 20.0f, 1.0f, 0xFFFFFF00, "Punchthrough");
   else				KMABCTablePrint3D (20.0f, 20.0f, 1.0f, 0xFFFFFF00, "Translucency");

   if (bStart==FALSE)  
	{
		KMABCTablePrint3D (20.0f, 50.0f, 0.6f, 0xFFFFFFFF, "Press START");
	}
	if (bStart==TRUE)
	{
	   KMABCTablePrint3D (20.0f, 50.0f, 0.6f, 0xFFFFFFFF, "CURSOR to move camera.");
	}
  
   nFrame++;

   /* RenderScene OK */
	return TRUE;


}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : PadControl()                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     :                            
 *-------------------------------------------------------------------------------------*/
void PadControl (void)
{	
static	int	Delay = 0;

	Delay++;

	/* START */
	if (IsSTARTKey())
	{
		if (Delay>10) bStart = !bStart;
		Delay = 0;
	}
	
	/* No controler until START is pressed */
	if (bStart == FALSE) return;
	
	/* UP */
	if (IsUPKey())
	{
		Distance -= 0.1f;
	}

	/* DOWN */
	if (IsDOWNKey())
	{
		Distance -= 0.1f;
	}

	/* LEFT */
	if (IsLEFTKey())
	{
		Ang  += 0.1f;
	}

	/* RIGHT */
	if (IsRIGHTKey())
	{
		Ang  -= 0.1f;
	}


	/* A button */
	if (IsAKey())
	{
	}
	
	/* B button */
	if (IsBKey())
	{
	}
		
	/* X button */
	if (IsXKey())
	{
	}

	/* Y button */
	if (IsYKey())
	{
	}

	/* LEFT finger button */
	if (IsLFKey())
	{
	}

	/* RIGHT finger button */
	if (IsRFKey())
	{
	}

}
/**************************************************************************************/
/*                                                                                    */
/*                            Aplication functions                                    */
/*                                                                                    */
/**************************************************************************************/
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : InitMeshes                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    : Shad, Mesh, TempVert, TempNormals                                  
 *  Description     : Sets initials values for meshes managing                            
 *-------------------------------------------------------------------------------------*/
void InitMeshes (void)
{
register unsigned i,j, k=0;

	/* Memory allocation for KmVert */
	for (i=0; i<NUM_MESHES; i++) 
	{
		KmVert[i] = (KMVERTEX_03 *)MemPtr; 
		MemPtr += ((KMDWORD)(Mesh[i].nNumVertex*sizeof(KMVERTEX_03)) + 0x1F) & ~0x1F; /* 32Byte Alignment */
	}

	/* Setting UV values and colors for all the meshes */
    for (i=0; i<NUM_MESHES;i++)
	{
		for (j=0; j<Mesh[i].nNumVertex; j++)
		{
            (KmVert[i]+j)->fU = *(Mesh[i].pUV+j*2+0);
            (KmVert[i]+j)->fV = *(Mesh[i].pUV+j*2+1);

			(KmVert[i]+j)->uBaseRGB.dwPacked	= 0xFFFFFFFF;
			(KmVert[i]+j)->uOffsetRGB.dwPacked	= 0x00000000;
		
		} 
				
   }

}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : InitMaterials                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     : Loads textures and sets vertex contexts                           
 *-------------------------------------------------------------------------------------*/
void InitMaterials (void)
{
	/* OPAQUE MATERIALS */
	KMShellLoadTexture (&Tex[M_SNOW],(unsigned long *)Snow, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[M_SNOW], &Tex[M_SNOW], VC_OPAQUE);

	KMShellLoadTexture (&Tex[20],(unsigned long *)Back, 32,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[20], &Tex[20], VC_OPAQUE);

	KMShellLoadTexture (&Tex[M_LOGO],(unsigned long *)VideoL, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[M_LOGO], &Tex[M_LOGO], VC_OPAQUE);


	KMShellLoadTexture (&Tex[M_B1_BARK],(unsigned long *)Bark, 64,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[M_B1_BARK], &Tex[M_B1_BARK], VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_B2_TRUNK], &Tex[M_B1_BARK], VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_B3_TRUNK], &Tex[M_B1_BARK], VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_B4_BARK], &Tex[M_B1_BARK], VC_OPAQUE);

	/* TRANSLUCENT MATERIALS */
	KMShellLoadTexture (&Tex[M_B1_TRANS],(unsigned long *)Bush, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B1_TRANS], &Tex[M_B1_TRANS],VC_TRANS | VC_UVFLIP);
	
	KMShellLoadTexture (&Tex[M_B2_TRANS],(unsigned long *)branch2, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B2_TRANS], &Tex[M_B2_TRANS], VC_TRANS | VC_UVFLIP);
	
	KMShellLoadTexture (&Tex[M_B3_TRANS],(unsigned long *)Pine, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B3_TRANS], &Tex[M_B3_TRANS], VC_TRANS | VC_UVFLIP);
	
	KMShellLoadTexture (&Tex[M_B4_TRANS],(unsigned long *)Pine4, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext  (&VertexContext[M_B4_TRANS], &Tex[M_B4_TRANS], VC_TRANS | VC_UVFLIP);

	/* PUNCHTROUGH MATERIALS */
	KMShellLoadTexture (&Tex[M_B1_TRANS],(unsigned long *)Bush, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B1_TRANS + 100], &Tex[M_B1_TRANS], VC_PUNCHTHROUGH | VC_UVFLIP);
	
	KMShellLoadTexture (&Tex[M_B2_TRANS],(unsigned long *)branch2, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B2_TRANS + 100], &Tex[M_B2_TRANS], VC_PUNCHTHROUGH | VC_UVFLIP);

	KMShellLoadTexture (&Tex[M_B3_TRANS],(unsigned long *)Pine, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B3_TRANS + 100], &Tex[M_B3_TRANS], VC_PUNCHTHROUGH | VC_UVFLIP);
	
	KMShellLoadTexture (&Tex[M_B4_TRANS],(unsigned long *)Pine4, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_ARGB1555);
	KMShellInitVertexContext (&VertexContext[M_B4_TRANS + 100], &Tex[M_B4_TRANS], VC_PUNCHTHROUGH | VC_UVFLIP);

}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : RenderObject                                                       
 *  Inputs          : Object                                                             
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                                                    
 *  Description     : Sending a set of triangles to render.                              
 *-------------------------------------------------------------------------------------*/
void RenderObject (MATRIX *Matrx, int Object)
{
	KMTransTransformProjectPerspective (Matrx, Mesh[Object].nNumVertex, Mesh[Object].pVertex, 
										KmVert[Object], ScreenWidth, ScreenHeight,
										CameraFrom, CameraTo, 0.0f, 1.0f, 1000000.0f, 60.0f*(PI/180.0f));
	
	KMShellStrips (&VertexContext[Object+nPT],Mesh[Object].nNumStrips, Mesh[Object].pStripLength, Mesh[Object].pStrips, (KMVERTEX_03 *)KmVert[Object]);
}







