/*****************************************************************************
  Name :     CheapBump 
  Author:	 Carlos Sarria
  Date :     April 1999 
  Platform : Dreamcast Set5 (CLX2 + SH4)
 
  Description : Very cheap BumpMap.

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

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

/* 3D data */     
#include "CheapBump.h"
 
/* Textures have been loaded with Data.c */
extern const unsigned char Ground[];
extern const unsigned char GroundBump[];

extern const unsigned char Back[];
extern const unsigned char Light[];

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

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

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

/* Camera data */
int ScreenWidth=640, ScreenHeight=480;

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

/* Generic data */
unsigned nFrame = 0, nCurrentTexture = 0, CreationMethod = 1, CurrentObject = 2;

/* Object angles */
float fAng1 = 0.0f , fAng2 = 0.0f, fAng3 = 0.0f;

/* Camera distance */
float fDist = 75.0f;

/* Light angle */
float fLAng1 = -0.5f, fLAng2 = 1.0f;


/**************************************************/
/* Prototypes                                     */
/**************************************************/
void	InitMeshes			(void);
void	InitMaterials		(void);
void	InitBumpmapMesh		(int Object);

/************************************************************************/
/* KMShell functions:                                                   */
/*    KMInitApplication                                                 */
/*    KMQuitApplication                                                 */
/*    KMRenderScene                                                     */
/*    KMPadControl                                                      * 
/*                                                                      */
/* WARNING : These functions must be created always because are called  */
/*           by KMShell.											    */
/************************************************************************/
/*----------------------------------------------------------------------*
 *  Function Name   :  InitApplication                              
 *  Inputs          :  None                                               
 *  Outputs         :  None                                                 
 *  Returns         :                                              
 *  Globals Used    :                                                
 *  Description     :   KMInitApplication() is called by KMShell to enable
 *						user to initialise the application                                           
 *----------------------------------------------------------------------*/
void InitApplication (void)
{
	KMShellSetVideo	(FALSE		/* Trans PreSort   */
					 );

	KMShellSetBuffers(50, 		/* % Opaque        */
					  0,		/* % ModVol Opaque */
					  50,		/* % Translucent   */
					  0,		/* % ModVol Trans  */
					  0			/* % Punchthrough  */
					  );		

	KMABCTableInit (TRUE);

	InitMaterials ();
 
	InitMeshes();
	
	LightDirection[0] = cos(fLAng2) * cos(fLAng1);
	LightDirection[1] = sin(fLAng1);
	LightDirection[2] = sin (fLAng2) * cos(fLAng1);

	
}
/*----------------------------------------------------------------------*
 *  Function Name   :                                   
 *  Inputs          :  None                                               
 *  Outputs         :  None                                                 
 *  Returns         :                                            
 *  Globals Used    :                                                 
 *  Description     :                                                  
 *----------------------------------------------------------------------*/
void QuitApplication (void)
{
	
}
/*----------------------------------------------------------------------*
 *  Function Name   :  KMRenderScene                                      
 *  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			i, j;
km_vector   Light;

	KMShellBackground(&VertexContext[2]);

   	/* CurrentObject is a standard object and CurrentObject+1 is the bumpmap object on top of the standard one.
	 * For this demo, both objects are appart for clarity, but the same object can be used twice. 
	 */
	KMMatrixReset	  (&Matrx);
	KMMatrixRotate    (&Matrx,  0.0f, fAng1, fAng2);
	KMMatrixTranslate (&Matrx, 0.0f, 0.0f, fDist);  
   
	/* Vertices transformation */
	KMTransTransformProjectPerspective (&Matrx, Mesh[M_OBJECT].nNumVertex, Mesh[M_OBJECT].pVertex, 
										KmVert[M_OBJECT], ScreenWidth, ScreenHeight,
										CameraFrom, CameraTo, 0.0f, 1.0f, 1000000.0f, 60.0f*(PI/180.0f));
	
	/* Calculation of smooth-shading */ 
	KMLightSmoothShade (&Matrx, Mesh[M_OBJECT].nNumVertex, Mesh[M_OBJECT].pNormals, (KMVERTEX_03 *)KmVert[M_OBJECT],
								LightDirection, 0xC0FFFFFF, FALSE);

	/* Render strips (Base texture) */
	KMShellStrips (&VertexContext[1],
						Mesh[M_OBJECT].nNumStrips, Mesh[M_OBJECT].pStripLength, 
						Mesh[M_OBJECT].pStrips, (KMVERTEX_03 *)KmVert[M_OBJECT]);
					
	/* calculate 'cheap' bumpmap on the fly */
	 KMCheapBumpShade(&Matrx,  Mesh[M_OBJECT].nNumVertex, KmVert[M_OBJECT], LightDirection);
	
	KMShellStrips (&VertexContext[0],
						Mesh[M_OBJECT].nNumStrips, Mesh[M_OBJECT].pStripLength, 
						Mesh[M_OBJECT].pStrips, (KMVERTEX_03 *)KmVert[M_OBJECT]);

	/* Draw the light spot */
	KMMatrixReset	  (&Matrx);

	KMMatrixTranslate (&Matrx, -LightDirection[0] * 120.0f, -LightDirection[1] * 120.0f, fDist - LightDirection[2] * 120.0f);  


	KMTransTransformProjectPerspective (&Matrx, Mesh[M_LIGHT].nNumVertex, Mesh[M_LIGHT].pVertex, 
										KmVert[M_LIGHT], ScreenWidth, ScreenHeight,
										CameraFrom, CameraTo, 0.0f, 1.0f, 1000000.0f, 60.0f*(PI/180.0f));

	KMShellStrips (&VertexContext[3],
						Mesh[M_LIGHT].nNumStrips, Mesh[M_LIGHT].pStripLength, 
						Mesh[M_LIGHT].pStrips, (KMVERTEX_03 *)KmVert[M_LIGHT]);

  
	/* Screen text */
	KMABCTablePrint3D (20.0f, 20.0f, 1.0f, 0xFFFFFF00, "CheapBumpmap");
	KMABCTablePrint3D (20.0f, 50.0f, 0.6f, 0xFFFFFFFF, "CURSOR to move object.");
	KMABCTablePrint3D (20.0f, 70.0f, 0.6f, 0xFFFFFFFF, "CURSOR-A to rotate light.");
	KMABCTablePrint3D (20.0f, 90.0f, 0.6f, 0xFFFFFFFF, "TRIGGERS to zoom.");

	/* If the light is close to 0 display a warning message */	
	Light[0] = -LightDirection[0];
	Light[1] = -LightDirection[1];
	Light[2] = -LightDirection[2];

	KMMatrixNormalize (Light);

	if (sqrt(Light[0]*Light[0] + Light[1]*Light[1]) < 0.1f)
		KMABCTablePrint3D (20.0f, 450.0f, 0.6f, 0xFFFFFF00, "WRONG LIGHTING AREA");

	
	nFrame++;
  
	/* RenderScene OK */
	return TRUE;
}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : KMPadControl()                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     : This function is called by KMShell to control the Pad.                           
 *-------------------------------------------------------------------------------------*/
void PadControl (void)
{	
static	int	Delay = 0;

	Delay++;

	/* START */
	if (IsSTARTKey())
	{
		if (Delay>10)
		{
			/* Generic data */
			nFrame = 0;

			/* Object angles */
			fAng1 = 0.0f ; fAng2 = 0.0f; fAng3 = 0.0f;

			/* Camera distance */
			fDist = 75.0f;

			/* Light angle */
			fLAng1 = -0.5f; fLAng2 = 1.0f;

			LightDirection[0] = cos(fLAng2) * cos(fLAng1);
			LightDirection[1] = sin(fLAng1);
			LightDirection[2] = sin (fLAng2) * cos(fLAng1);
		}
		Delay = 0;
	}

	/* UP */
	if (IsUPKey())
	{
			/* Light rotation */
		if (IsAKey()) 
		{
			LightDirection[0] = cos(fLAng2) * cos(fLAng1);
			LightDirection[1] = sin(fLAng1);
			LightDirection[2] = sin (fLAng2) * cos(fLAng1);
			fLAng1 -= 0.02f;
		}
		else fAng2 += 0.05f;   
	}

	/* DOWN */
	if (IsDOWNKey())
	{
			/* Light rotation */
		if (IsAKey()) 
		{
			LightDirection[0] = cos(fLAng2) * cos(fLAng1);
			LightDirection[1] = sin(fLAng1);
			LightDirection[2] = sin (fLAng2) * cos(fLAng1);
			fLAng1 += 0.02f;
		}
		else fAng2 -= 0.05f;  
		
	}

	/* LEFT */
	if (IsLEFTKey())
	{
		/* Light rotation */
		if (IsAKey()) 
		{
			LightDirection[0] = cos(fLAng2) * cos(fLAng1);
			LightDirection[1] = sin(fLAng1);
			LightDirection[2] = sin (fLAng2) * cos(fLAng1);
			fLAng2 -= 0.02f;
		}
		
		else  fAng1  += 0.05f;
	}

	/* RIGHT */
	if (IsRIGHTKey())
	{
		/* Light rotation */
		if (IsAKey()) 
		{
			LightDirection[0] = cos(fLAng2) * cos(fLAng1);
			LightDirection[1] = sin(fLAng1);
			LightDirection[2] = sin (fLAng2) * cos(fLAng1);
			fLAng2 += 0.02f;
		}
		
		else   fAng1  -= 0.05f;
	}


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

	}

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

	/* LEFT finger button */
	if (IsLFKey())
	{
		/* Zoom in */
		if (fDist>-40) fDist -= 10.0f; 
		
	}

	/* RIGHT finger button */
	if (IsRFKey())
	{
		/* Zooom out */
		if (fDist<250) fDist += 10.0f;
	}

}
/**************************************************************************************/
/*                                                                                    */
/*                            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;
float fTempVert[3], fModule;


	/* Memory allocation for KmVert */
	for (i=0; i<NUM_MESHES; i++) 
	{
		/* Object */
		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++)
		{
			if(i==M_LIGHT)
			{
				(KmVert[i]+j)->fU = *(Mesh[i].pUV+j*2+0); 
				(KmVert[i]+j)->fV = *(Mesh[i].pUV+j*2+1); 
			}
			else
			{
				(KmVert[i]+j)->fU = *(Mesh[i].pUV+j*2+0) * 4.0f; 
				(KmVert[i]+j)->fV = *(Mesh[i].pUV+j*2+1) * 4.0f; 
			}

			(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)
{

	/* BUMP MATERIALS */
	KMShellLoadTexture (&Tex[0],(unsigned long *)GroundBump, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellInitVertexContext (&VertexContext[0], &Tex[0], VC_TRANS | VC_SPECULAR);

	/* OPAQUE MATERIALS */
	KMShellLoadTexture (&Tex[1],(unsigned long *)Ground, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[1], &Tex[1], VC_OPAQUE);

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

	KMShellLoadTexture (&Tex[3],(unsigned long *)Light, 128,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[3], &Tex[3], VC_ADDITIVE);
}

/*--------------------------------------------------------------------------------------*/
/*---------------------------------- END OF FILE ---------------------------------------*/
/*--------------------------------------------------------------------------------------*/





