/*****************************************************************************
  Name :     Knot 
  Author:	 Carlos Sarria
  Date :     August 1998 
  Platform : Dreamcast Set5 (CLX2 + SH4)
 
  Description : BumpMap demo.

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

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

#define	  BUMP_START 20

#ifndef M_KNOT
#define M_KNOT 0
#endif

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


BOOL bStart = FALSE;

float fAng1 = 0.0f , fAng2 = 0.0f, fAng3 = 0.0f, fZ;
float fLAng1 = -1.0 , fLAng2 = 1.0;


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

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

float *pBump[256];

/* 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 = 500;

/**************************************************/
/* Prototypes                                     */
/**************************************************/
void	InitMeshes			(void);
void	InitMaterials		(void);
void	RenderBumpmap		(MATRIX *Matrx, 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(35, 		/* % Opaque        */
					  0,		/* % ModVol Opaque */
					  65,		/* % Translucent   */
					  0,		/* % ModVol Trans  */
					  0			/* % Punchthrough  */
					  );		

	KMABCTableInit (TRUE);

	InitMaterials ();

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

	/* FREE TEXTURES */
	kmFreeTexture(&Tex[M_KNOT]);
	kmFreeTexture(&Tex[M_KNOT+BUMP_START]);
	
}

/*----------------------------------------------------------------------*
 *  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;
register	i, j;
static float	fAngleOffset = 0.0f, fLightOffset = 0.0f;
extern unsigned Pad;

	if (bStart==FALSE)
	{
		if ((nFrame%1000) < 300) fAngleOffset++;
		else					 fLightOffset++;

		fLAng1 = cos(fLightOffset/60.0f) * 1.5f;
		fLAng2 = sin(fLightOffset/30.0f) * 1.5f;

		fAng1 = cos(fAngleOffset/200.0f) * PI*2.0f;
		fAng2 = sin(fAngleOffset/200.0f) * PI*2.0f;
	}

   LightDirection[0] = fLAng2;
   LightDirection[1] = fLAng1;
   LightDirection[2] = 1.0f;

   KMMatrixReset(&Matrx);

   if (bStart==FALSE)
   {
	   fAng1 += 0.01f;
	   fAng2 += 0.01f;
   }
  
   
   KMMatrixRotate    (&Matrx, 0.0f, fAng1, fAng2);
   KMMatrixTranslate (&Matrx, 0.0f, 0.0f, 200.0f);  

   RenderBumpmap   (&Matrx, M_KNOT);
     
   KMABCTablePrint3D (20.0f, 20.0f, 1.0f, 0xFFFFFF00, "BumpMap");

   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 object.");
	   KMABCTablePrint3D (20.0f, 70.0f, 0.6f, 0xFFFFFFFF, "CURSOR-A to move light.");
   }
  
   nFrame++;
  
   /* RenderScene OK */
	return TRUE;

}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : KMPadControl()                                                         
 *  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())
	{
		if (IsAKey())  fLAng1 -= 0.1f;
		else           fAng1 += 0.05f;
	}

	/* DOWN */
	if (IsDOWNKey())
	{
		if (IsAKey())  fLAng1 += 0.1f;
		else           fAng1  -= 0.05f;
	}

	/* LEFT */
	if (IsLEFTKey())
	{
		if (IsAKey()) fLAng2 += 0.1f;
		else          fAng2  += 0.05f;
	}

	/* RIGHT */
	if (IsRIGHTKey())
	{
		if (IsAKey()) fLAng2 -= 0.1f;
		else          fAng2  -= 0.05f;
	}


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


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

		/* Bump-map */ 
		KmVert[i+BUMP_START] = (KMVERTEX_03 *)MemPtr; 
		MemPtr += ((KMDWORD)(Mesh[i].nNumVertex*sizeof(KMVERTEX_03)) + 0x1F) & ~0x1F; /* 32Byte Alignment */

		/* 
		 * Local coordenates system for bump-mapping.
		 * 3 floats for Tanget axis, 3 floats for Binormal Axis
		 * and 1 float more to store the angle Theta.
		 */
		pBump[i] = (float *)MemPtr; 
		MemPtr += ((KMDWORD)(Mesh[i].nNumVertex*sizeof(float)*7) + 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++)
		{
			/* 
			 * UVs have been multiplied by a number to get a more wide
			 * range. It's neccessary for this model ONLY.
			 */
			(KmVert[i]+j)->fU = *(Mesh[i].pUV+j*2+0)*18.0f; 
            (KmVert[i]+j)->fV = *(Mesh[i].pUV+j*2+1)*2.0f; 

			(KmVert[i+BUMP_START]+j)->fU = *(Mesh[i].pUV+j*2+0)*18.0f; 
            (KmVert[i+BUMP_START]+j)->fV = *(Mesh[i].pUV+j*2+1)*2.0f; 
		
			(KmVert[i]+j)->uBaseRGB.dwPacked	= 0x80808080;
			(KmVert[i]+j)->uOffsetRGB.dwPacked	= 0x80008080;
		
		} 

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

}
/*-------------------------------------------------------------------------------------* 
 *  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_KNOT],(unsigned long *)Wood, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellInitVertexContext (&VertexContext[M_KNOT], &Tex[M_KNOT], VC_OPAQUE | VC_UVFLIP);

	/* BUMP MATERIALS */
	KMShellLoadTexture (&Tex[M_KNOT+BUMP_START],(unsigned long *)bVL, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_BUMP );
	KMShellInitVertexContext (&VertexContext[M_KNOT+BUMP_START], &Tex[M_KNOT+BUMP_START], VC_TRANS | VC_SPECULAR);


}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : RenderObject                                                       
 *  Inputs          : Object                                                             
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                                                    
 *  Description     : Sending a set of triangles to render.                              
 *-------------------------------------------------------------------------------------*/
void RenderBumpmap (MATRIX *Matrix, int Object)
{
register i;

	/* Transforming our object */
	KMTransTransformProjectPerspective (Matrix, Mesh[Object].nNumVertex, Mesh[Object].pVertex, 
										KmVert[Object], ScreenWidth, ScreenHeight,
										CameraFrom, CameraTo, 0.0f, 1.0f, 1000000.0f, 60.0f*(PI/180.0f));

	/* Copiying the information into the bumpmap object */
	for (i=0; i<Mesh[Object].nNumVertex; i++)
	{
		(KmVert[Object+BUMP_START]+i)->fX   = (KmVert[Object]+i)->fX;
		(KmVert[Object+BUMP_START]+i)->fY   = (KmVert[Object]+i)->fY;
		(KmVert[Object+BUMP_START]+i)->u.fZ = (KmVert[Object]+i)->u.fZ; 
	}

	/* Calculation of smooth-shading and bump-map in one go */ 
	KMBumpShade (Matrix, Mesh[Object].nNumVertex, pBump[Object], Mesh[Object].pNormals,
				KmVert[Object+BUMP_START], KmVert[Object],	LightDirection);
				
	
	/* Smooth shaded solid object */
	KMShellStrips (&VertexContext[Object],
					Mesh[Object].nNumStrips, Mesh[Object].pStripLength, 
					Mesh[Object].pStrips, (KMVERTEX_03 *)KmVert[Object]);

	/* Bumpmap */
	KMShellStrips (&VertexContext[Object+BUMP_START],
					Mesh[Object].nNumStrips, Mesh[Object].pStripLength, 
					Mesh[Object].pStrips, (KMVERTEX_03 *)KmVert[Object+BUMP_START]);


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






