/*****************************************************************************
  Name :     Materials 
  Author:	 Carlos Sarria
  Date :     April 1999 
  Platform : Dreamcast Set5 (CLX2 + SH4)
 
  Description : BumpMap materials demo.

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

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

/* 3D data */     
#include "Materials.h"
 
/* Textures have been loaded with Data.c */
extern const unsigned char WoolBmp[];
extern const unsigned char CracksBmp[];
extern const unsigned char FiberBmp[];
extern const unsigned char Lizard1Bmp[];
extern const unsigned char Lizard2Bmp[];
extern const unsigned char GolfBmp[];
extern const unsigned char EgyptBmp[];
extern const unsigned char BrickBmp[];
extern const unsigned char StonesBmp[];
extern const unsigned char GoldBmp[];

extern const unsigned char Wool[];
extern const unsigned char Golf[];
extern const unsigned char Cracks[];
extern const unsigned char Fiber[];
extern const unsigned char Lizard1[];
extern const unsigned char Lizard2[];
extern const unsigned char Egypt[];
extern const unsigned char Brick[];
extern const unsigned char Stones[];
extern const unsigned char Gold[];

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*/

/* Bumpmap data */
float *pBump[256];

/* 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, Show=FALSE, BumpMethod = 0;

/* 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 	LoadTextures 		(void);
void 	CreateContexts 		(int Mode);
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);

	LoadTextures 	();
	CreateContexts 	(0);
 
	InitMeshes();

	InitBumpmapMesh (M_STARBUMP);
	InitBumpmapMesh (M_SPHEREBUMP);
	InitBumpmapMesh (M_BOXBUMP);
	
	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, BumpmapObject;
char	*Textures[]={"WOOL", "GOLF","LIZARD1","LIZARD2","SKIN","FIBER","EGYPT","BRICK","STONES","GOLD"};
char	*Objects[]={"STAR", "SPHERE","SLAB"};
char	*BMethod[]={ "STANDARD", "TRANSLUCENT", "HIGHLIGHT"};


	KMShellBackground(&VertexContext[20]);

   	/* 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. 
	 */
	BumpmapObject = CurrentObject + 1; 
 
	KMMatrixReset	  (&Matrx);  
	KMMatrixRotate    (&Matrx,  0.0f, fAng1, fAng2);
	KMMatrixTranslate (&Matrx, 0.0f, 0.0f, fDist);  
   
	/* Vertices transformation */
	KMTransTransformProjectPerspective (&Matrx, Mesh[CurrentObject].nNumVertex, Mesh[CurrentObject].pVertex, 
										KmVert[CurrentObject], ScreenWidth, ScreenHeight,
										CameraFrom, CameraTo, 0.0f, 1.0f, 1000000.0f, 60.0f*(PI/180.0f));

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

	/* Calculation of smooth-shading and bump-map in one go */ 
	KMBumpShade (&Matrx, Mesh[BumpmapObject].nNumVertex, pBump[BumpmapObject], Mesh[BumpmapObject].pNormals,
						KmVert[BumpmapObject], KmVert[CurrentObject], LightDirection, BumpMethod);


	/* Render bump layer */
	KMShellStrips (&VertexContext[nCurrentTexture],
						Mesh[BumpmapObject].nNumStrips, Mesh[BumpmapObject].pStripLength, 
						Mesh[BumpmapObject].pStrips, (KMVERTEX_03 *)KmVert[BumpmapObject]);
						
	/* Render base layer */
	KMShellStrips (&VertexContext[10+nCurrentTexture],
						Mesh[CurrentObject].nNumStrips, Mesh[CurrentObject].pStripLength, 
						Mesh[CurrentObject].pStrips, (KMVERTEX_03 *)KmVert[CurrentObject]);
	
	/* Draw the light spot */
	if (Show==TRUE)
	{
		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[21],
						Mesh[M_LIGHT].nNumStrips, Mesh[M_LIGHT].pStripLength, 
						Mesh[M_LIGHT].pStrips, (KMVERTEX_03 *)KmVert[M_LIGHT]);
						
		Show=FALSE;
	}

  
	/* Screen text */
	KMABCTablePrint3D (20.0f, 20.0f, 1.0f, 0xFFFFFF00, "BumpMaterials");
	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.");


	KMABCTablePrint3D (20.0f, 410.0f, 0.6f, 0xFFFFFFFF, "(X) Bump method: %s", BMethod[BumpMethod]);
	KMABCTablePrint3D (20.0f, 430.0f, 0.6f, 0xFFFFFFFF, "(B) Texture: %s", Textures[nCurrentTexture]);
	KMABCTablePrint3D (20.0f, 450.0f, 0.6f, 0xFFFFFFFF, "(Y) Object: %s", Objects[CurrentObject>>1]);
	
	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())
	{
		Show=TRUE;
	}
	
	/* B button */
	if (IsBKey())
	{
		if (Delay>2) {nCurrentTexture++; if(nCurrentTexture==10) nCurrentTexture=0;}
		Delay = 0;
	}
		
	/* X button */
	if (IsXKey())
	{
		if (Delay>2) {BumpMethod++; if(BumpMethod==3) BumpMethod=0; CreateContexts (BumpMethod);}
		Delay = 0;
	
	}

	/* Y button */
	if (IsYKey())
	{
		if (Delay>2)
		{
			CurrentObject += 2; if(CurrentObject==6) CurrentObject = 0;
		}
		Delay = 0;
	}

	/* 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_BOX || i== M_BOXBUMP || 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   : InitBumpmapMesh                                                  
 *  Inputs          : None                                                                 
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                 
 *  Description     : Sets the 'Tangent Space' coordinate system for every vertex to be 
 *					  bumpmapped.                            
 *-------------------------------------------------------------------------------------*/
void InitBumpmapMesh (int Object)
{	
		/* 
		 * Local coordenates system for bump-mapping.
		 * 3 floats for Tanget axis, 3 floats for Binormal Axis
		 */
		pBump[Object] = (float *)MemPtr; 
		MemPtr += ((KMDWORD)(Mesh[Object].nNumVertex*sizeof(float)*6) + 0x1F) & ~0x1F; /* 32Byte Alignment */

		/* 
		 * That is the function that calculates the local coordenate system
		 * for every single vertex. The information is stored in pBump[]
		 */
		KMBumpCalculateLocalCoords (pBump[Object], BUMP_COORDS_ANYDIRECTION,
									Mesh[Object].nNumVertex, Mesh[Object].pVertex, Mesh[Object].pNormals, Mesh[Object].pUV,
									Mesh[Object].nNumFaces, Mesh[Object].pFaces);	


}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : LoadTextures                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     : Loads textures and sets vertex contexts                           
 *-------------------------------------------------------------------------------------*/
void LoadTextures (void)
{

	/* BUMP MATERIALS */
	KMShellLoadTexture (&Tex[0],(unsigned long *)WoolBmp, 256,    KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP);
	KMShellLoadTexture (&Tex[1],(unsigned long *)GolfBmp, 256,    KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[2],(unsigned long *)Lizard1Bmp, 256, KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[3],(unsigned long *)Lizard2Bmp, 256, KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[4],(unsigned long *)CracksBmp, 256,  KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[5],(unsigned long *)FiberBmp, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[6],(unsigned long *)EgyptBmp, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[7],(unsigned long *)BrickBmp, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[8],(unsigned long *)StonesBmp, 256,  KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellLoadTexture (&Tex[9],(unsigned long *)GoldBmp, 256,    KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	
	/* BASE MATERIALS */
	KMShellLoadTexture (&Tex[10],(unsigned long *)Wool, 128,   	KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[11],(unsigned long *)Golf, 128,    KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[12],(unsigned long *)Lizard1, 128, KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[13],(unsigned long *)Lizard2, 128, KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[14],(unsigned long *)Cracks, 128,  KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[15],(unsigned long *)Fiber, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[16],(unsigned long *)Egypt, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[17],(unsigned long *)Brick, 128,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[18],(unsigned long *)Stones, 128,  KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[19],(unsigned long *)Gold, 128,    KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	
	KMShellLoadTexture (&Tex[20],(unsigned long *)Back, 256,    KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[21],(unsigned long *)Light, 128,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	
}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : LoadTextures                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     : Loads textures and sets vertex contexts                           
 *-------------------------------------------------------------------------------------*/
void CreateContexts (int Mode)
{
register i;

	KMShellInitVertexContext (&VertexContext[20], &Tex[20], VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[21], &Tex[21], VC_ADDITIVE);

	for (i=0; i<10; i++)
	{
		switch (Mode)
		{
			case 0: 
			/* STANDARD */
				/* Bump Materials */
				KMShellInitVertexContext (&VertexContext[i], &Tex[i], VC_OPAQUE | VC_SPECULAR | VC_DECALALPHA);
				/* Base Materials */
				KMShellInitVertexContext (&VertexContext[10+i], &Tex[10+i], VC_TRANS);
				VertexContext[10+i].SRCBlendingMode		= KM_DESTCOLOR;
				VertexContext[10+i].DSTBlendingMode		= KM_ZERO;
				kmProcessVertexRenderState(&VertexContext[10+i]);
				break;
				
			case 1: 
			/* TRANSLUCENT */
				/* Bump Materials */
				KMShellInitVertexContext (&VertexContext[i], &Tex[i], VC_TRANS | VC_SPECULAR);
				/* Base Materials */
				KMShellInitVertexContext (&VertexContext[10+i], &Tex[10+i], VC_OPAQUE);
				break;
			
			case 2: 
			/* ADDITIVE */
				/* Bump Materials */
				KMShellInitVertexContext (&VertexContext[i], &Tex[i], VC_OPAQUE | VC_SPECULAR | VC_DECALALPHA);
				/* Base Materials */
				KMShellInitVertexContext (&VertexContext[10+i], &Tex[10+i], VC_ADDITIVE);
				break;
				
			}
	}
}

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





