/*****************************************************************************
  Athor:	 Carlos Sarria	
  Name :     Scanner
  Date :     July 1998
  Platform : Dreamcast Set5 (CLX2 + SH4) 
 
  Description : Generic modifier volume demo.

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

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

/* Textures have been loaded with Data.c */
extern const unsigned char backgrnd[];
extern const unsigned char VideoL[];
extern const unsigned char Dino[];
extern const unsigned char Scanner[];
extern const unsigned char Surface[];
extern const unsigned char Bones[];

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


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

/* texture surface */
KMSURFACEDESC		Tex[256];				
/* Vertex context */
KMVERTEXCONTEXT		VertexContext[256];		
KMVERTEXCONTEXT     Context, MV_Dino[4], MV_Scanner[3];	
/* Vertex pointers*/
KMVERTEX_03			*KmVert[256];		

extern KMVERTEXBUFFDESC VertexBufferDesc;	/* is defined in KMShell.c */

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

float   nFrame = 0;
float	fXPos, fYPos;
float   MachineAngle = 0.0f, ScannerAngle = 0.0f;

BOOL    bStart = FALSE;

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

void	InitMeshes			(void); 
void    InitMaterials       (void);
void	RenderObject		(int Object, KMVERTEXCONTEXT *VertexContext);

void	ModVolContext		(void);
void	RenderObjectMV		(int);
void	RenderObjectSHV		(int Object);

void	kmtri_stripsMV		(KMVERTEXBUFFDESC BufferDesc, unsigned nNumStrips, unsigned short *pLen, 
								unsigned short *pStrips, KMVERTEX_03 *pVertices);

void	kmtri_trianglesSHV (KMVERTEXBUFFDESC BufferDesc, unsigned nNumFaces, unsigned short *pFaces,
								KMVERTEX_03	*pVertices);


/************************************************************************/
/* 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 (	33, 		/* % Opaque        */
					0,			/* % ModVol Opaque */
					33,			/* % Translucent   */
					33,			/* % ModVol Trans  */
					0);	

	KMABCTableInit (TRUE);

	InitMaterials ();

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

	/* FREE TEXTURES */
	kmFreeTexture(&Tex[M_BONES]);
	kmFreeTexture(&Tex[M_SURFACE]);
	kmFreeTexture(&Tex[M_SCANNER]);
	kmFreeTexture(&Tex[M_SURFACE]);
	kmFreeTexture(&Tex[10]);
	kmFreeTexture(&Tex[M_DINOSKIN]);
	kmFreeTexture(&Tex[M_SCANNER]);
	kmFreeTexture(&Tex[M_LOGO]);	

}

/*----------------------------------------------------------------------*
 *  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)
{
int i;
MATRIX Matrx;

   KMShellBackground (&VertexContext[10]);
   
   if (bStart == FALSE)
   {
		MachineAngle += PI/500.0f;
		ScannerAngle += PI/75.0f;
   }
   
   for (i=0; i<NUM_MESHES;i++)
   {

		KMMatrixReset(&Matrx);

		if (i==M_SCANNER)
		{
			KMMatrixRotate(&Matrx, -ScannerAngle, 0.0f, 0.0f);
			KMMatrixTranslate (&Matrx, 0.0f, 0.0f, 100.0f * sin(ScannerAngle));
		}

		KMMatrixRotate(&Matrx, 0.0f, 0.0f, -PI*0.02f);
		KMMatrixRotate(&Matrx, 0.0f, MachineAngle, 0.0f);
		KMMatrixTranslate (&Matrx, 0.0f, 0.0f, 110.0f); 

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

		if(i!=M_BONES && i!=M_SCANNER && i!=M_LOGO && i!=M_SURFACE01)
		{
			KMLightSmoothShade (&Matrx, Mesh[i].nNumVertex, Mesh[i].pNormals, (KMVERTEX_03 *)KmVert[i],
						LightDirection, 0xFFFFFFFF, FALSE);	

		}

		if (i==M_DINOSKIN) /* Modified volume (Dino's skin)*/
		{
			RenderObjectMV (i);
		}
		else  /* Standard object */
		{
			RenderObject (i, &VertexContext[i]);
		}

	}
   
	RenderObjectSHV (M_SCANNER); /* Modifier volume (Torus)*/

 
   KMABCTablePrint3D (10.0f, 20.0f, 1.0f, 0xFFFFFF00, "Modifier Volume");

   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 scanner.");
	}

   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())
	{
		ScannerAngle += 0.05f;
	}

	/* DOWN */
	if (IsDOWNKey())
	{
		ScannerAngle  -= 0.05f;
	}

	/* LEFT */
	if (IsLEFTKey())
	{
		MachineAngle  += 0.05f;
	}

	/* RIGHT */
	if (IsRIGHTKey())
	{
		MachineAngle  -= 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())
	{
	}

}
/*-------------------------------------------------------------------------------------*/
/*  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 += Mesh[i].nNumVertex*sizeof(KMVERTEX_03);
	}

	/* 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	= 0xA0FFFFFF;
			(KmVert[i]+j)->uOffsetRGB.dwPacked	= 0xFF000000;
		
		}     
	}
 
  
}
/*-------------------------------------------------------------------------------------* 
 *  Function Name   : InitMaterials                                                         
 *  Inputs          : None                                                               
 *  Outputs         : None                                                               
 *  Returns         : None                                                               
 *  Globals Used    :                                   
 *  Description     : Loads textures and sets vertex contexts                           
 *-------------------------------------------------------------------------------------*/
void InitMaterials (void)
{
	/* TEXTURES */
	KMShellLoadTexture (&Tex[M_BONES],(unsigned long *)Bones, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[M_DINOSKIN],(unsigned long *)Dino, 256,   KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[M_SURFACE],(unsigned long *)Surface, 256,  KM_TEXTURE_TWIDDLED_MM |  KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[M_SCANNER],(unsigned long *)Scanner, 256,  KM_TEXTURE_TWIDDLED_MM |  KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[10],(unsigned long *)backgrnd, 256,   KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565);
	KMShellLoadTexture (&Tex[M_LOGO],(unsigned long *)VideoL, 256,   KM_TEXTURE_TWIDDLED |  KM_TEXTURE_RGB565);
		
	/* VERTEX CONTEXT */
	KMShellInitVertexContext (&VertexContext[M_BONES],		&Tex[M_BONES],		VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_SURFACE],	&Tex[M_SURFACE],	VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_SURFACE01],	&Tex[M_SCANNER],	VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_COLLAR],		&Tex[M_SURFACE],	VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[10],			&Tex[10],			VC_OPAQUE);
	KMShellInitVertexContext (&VertexContext[M_DINOSKIN],	&Tex[M_DINOSKIN],	VC_TRANS );
	KMShellInitVertexContext (&VertexContext[M_SCANNER],	&Tex[M_SCANNER],	VC_TRANS | VC_CULLING);
	KMShellInitVertexContext (&VertexContext[M_LOGO],		&Tex[M_LOGO],		VC_OPAQUE);

	/* Setting a special context for our modifier volume */
	ModVolContext (); 
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   : RenderObject                                                     */
/*  Inputs          : Object                                                           */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    :                                                                  */
/*  Description     : Sending a set of triangles to render.                            */
/*-------------------------------------------------------------------------------------*/
void RenderObject (int Object, KMVERTEXCONTEXT *pVertexContext)
{
	KMShellStrips (pVertexContext, Mesh[Object].nNumStrips, Mesh[Object].pStripLength,
		          Mesh[Object].pStrips, KmVert[Object]);

}
/*----------------------------------------------------------------------*
 *  Function Name   :  RenderObjectMV                                      
 *  Inputs          :                                                    
 *  Outputs         :                                                   
 *  Returns         :                                                   
 *  Globals Used    :                                                   
 *  Description     :  This is the Dino's Skin                                                
 *----------------------------------------------------------------------*/
void RenderObjectMV (int Object)
{

	kmSetModifierRenderState (&MV_Dino[1]);
	kmSetVertexRenderState	 (&MV_Dino[0]);

	kmtri_stripsMV (VertexBufferDesc,	Mesh[Object].nNumStrips, Mesh[Object].pStripLength,
		            Mesh[Object].pStrips, KmVert[Object]);

}
/*----------------------------------------------------------------------*
 *  Function Name   :  RenderObjectSHV                                      
 *  Inputs          :                                                    
 *  Outputs         :                                                   
 *  Returns         :                                                   
 *  Globals Used    :                                                   
 *  Description     :  This is the Torus.                                                 
 *----------------------------------------------------------------------*/
void RenderObjectSHV (int Object)
{
	kmtri_trianglesSHV (VertexBufferDesc,  Mesh[Object].nNumFaces, Mesh[Object].pFaces, KmVert[Object]);
}

/*----------------------------------------------------------------------*/
/*  Function Name   :                                                   */
/*  Inputs          :                                                   */  
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void ModVolContext (void)
{
	/***************************************
	 * Modified Volume Context (Dino's skin)
	 ***************************************/

	/* Opaque Texture (Modifier A) */
	KMShellInitVertexContext (&MV_Dino[0],	&Tex[M_DINOSKIN], VC_TRANS);

	MV_Dino[0].RenderState		|= KM_MODIFIER;
	MV_Dino[0].SelectModifier	 = KM_MODIFIER_A;
	MV_Dino[0].RenderState		|= KM_FILTERMODE;
	MV_Dino[0].FilterMode		 = 2;
	MV_Dino[0].CullingMode		 = KM_NOCULLING;
	MV_Dino[0].RenderState		|= KM_STRIPLENGTH;
    MV_Dino[0].StripLength		 = KM_STRIP_04;

	kmProcessVertexRenderState(&MV_Dino[0]);

	/* Translucent texture */
	KMShellInitVertexContext (&MV_Dino[1],	&Tex[M_BONES],	VC_TRANS);

	MV_Dino[1].RenderState		|= KM_FILTERMODE;
	MV_Dino[1].FilterMode		 = 2;
	MV_Dino[1].CullingMode		 = KM_NOCULLING;
	MV_Dino[1].RenderState		|= KM_STRIPLENGTH;
    MV_Dino[1].StripLength		 =  KM_STRIP_04;

	kmProcessVertexRenderState(&MV_Dino[1]);

	/*********************************
	 * Modifier Volume Context (Torus)
	 *********************************/	

	/* First Polygon */
	MV_Scanner[0].RenderState			 = 0;
	MV_Scanner[0].RenderState			|= KM_PARAMTYPE;
	MV_Scanner[0].ParamType				 = KM_MODIFIERVOLUME;
	MV_Scanner[0].RenderState			|= KM_LISTTYPE;
	MV_Scanner[0].ListType				 = KM_TRANS_MODIFIER;
	MV_Scanner[0].ModifierInstruction	 = KM_MODIFIER_INCLUDE_FIRST_POLY;
	MV_Scanner[0].fBoundingBoxXmin		 =   0.0f; 
	MV_Scanner[0].fBoundingBoxYmin		 =   0.0f; 
	MV_Scanner[0].fBoundingBoxXmax		 = 639.0f;
	MV_Scanner[0].fBoundingBoxYmax		 = 479.0f; 
	
	kmProcessVertexRenderState(&MV_Scanner[0]);

	/* Normal Polygon */
	MV_Scanner[1].RenderState			 = 0;
	MV_Scanner[1].RenderState			|= KM_PARAMTYPE;
	MV_Scanner[1].ParamType				 = KM_MODIFIERVOLUME;
	MV_Scanner[1].RenderState			|= KM_LISTTYPE;
	MV_Scanner[1].ListType				 = KM_TRANS_MODIFIER;
	MV_Scanner[1].ModifierInstruction	 = KM_MODIFIER_NORMAL_POLY;
	MV_Scanner[1].fBoundingBoxXmin		 =   0.0f; 
	MV_Scanner[1].fBoundingBoxYmin		 =   0.0f; 
	MV_Scanner[1].fBoundingBoxXmax		 = 639.0f;
	MV_Scanner[1].fBoundingBoxYmax		 = 479.0f; 
	
	kmProcessVertexRenderState(&MV_Scanner[1]);

	/* Last Polygon */
	MV_Scanner[2].RenderState	= 0;
	MV_Scanner[2].RenderState	|= KM_PARAMTYPE;
	MV_Scanner[2].ParamType	= KM_MODIFIERVOLUME;
	MV_Scanner[2].RenderState	|= KM_LISTTYPE;
	MV_Scanner[2].ListType		= KM_TRANS_MODIFIER;
	MV_Scanner[2].ModifierInstruction = KM_MODIFIER_INCLUDE_LAST_POLY;
	MV_Scanner[2].fBoundingBoxXmin =   0.0f; 
	MV_Scanner[2].fBoundingBoxYmin =   0.0f; 
	MV_Scanner[2].fBoundingBoxXmax = 639.0f;
	MV_Scanner[2].fBoundingBoxYmax = 479.0f; 
	
	kmProcessVertexRenderState(&MV_Scanner[2]);
	
}

/*----------------------------------------------------------------------*
 *  Function Name   :   kmtri_stripsMV             
 *  Inputs          :                                      
 *  Outputs         :                                                  
 *  Returns         :                                                   
 *  Globals Used    :                                                
 *  Description     :   Special version of kmtri_strips for Modified Vol.                                                
 *                      Translation from KMVERTEX03 to KMVERTEX11.
 *----------------------------------------------------------------------*/
void kmtri_stripsMV (KMVERTEXBUFFDESC	BufferDesc,	unsigned nNumStrips, unsigned short *pLen, 
							unsigned short *pStrips, KMVERTEX_03 *pVertices)
{
int i, j;
int nVertices;
int nFace, nFacesCont=0;
KMVERTEX_11 Temp;
unsigned nPointer=0;

    Temp.uBaseRGB1m.dwPacked   = 0x80FFFFFF;
	Temp.uOffsetRGB0m.dwPacked = 0x00000000;
	Temp.uOffsetRGB1m.dwPacked = 0x00000000;

    for (j=0; j<nNumStrips; j++)
	{
		nVertices = *(pLen+j) + 1;

        nFacesCont = nPointer;

		kmxxGetCurrentPtr(&BufferDesc);
		kmxxStartVertexStrip(&BufferDesc);
	    
		for(i = nVertices; i >= 0; i--)
		{
			nFace = *(pStrips+nFacesCont++);
			(pVertices+nFace)->ParamControlWord	= (i!=0)?KM_VERTEXPARAM_NORMAL:KM_VERTEXPARAM_ENDOFSTRIP;

			kmxxSetVertex_11((pVertices+nFace)->ParamControlWord, 
							(pVertices+nFace)->fX, (pVertices+nFace)->fY, (pVertices+nFace)->u.fZ , 
							(pVertices+nFace)->fU, (pVertices+nFace)->fV,
 							(pVertices+nFace)->uBaseRGB.dwPacked, Temp.uOffsetRGB0m.dwPacked,
							(pVertices+nFace)->fU, (pVertices+nFace)->fV,
							Temp.uBaseRGB1m.dwPacked, Temp.uOffsetRGB1m.dwPacked);
	

		}

		nPointer+=nVertices+1;

		kmxxReleaseCurrentPtr(&BufferDesc);

	}						
}

/*----------------------------------------------------------------------*
 *  Function Name   :   kmtri_trianglesSHV             
 *  Inputs          :                                      
 *  Outputs         :                                                  
 *  Returns         :                                                   
 *  Globals Used    :                                                
 *  Description     :   Special version of kmtri_triangles for Modified Vol.                                                
 *                      Translation from KMVERTEX03 to KMVERTEX17.
 *----------------------------------------------------------------------*/
void kmtri_trianglesSHV ( KMVERTEXBUFFDESC	BufferDesc,	unsigned nNumFaces, unsigned short *pFaces, 
							KMVERTEX_03	*pVertices)
{
int nFace, nFacesCont=0, i;
KMVERTEX_17 Buffer;

	for(i = 0; i < nNumFaces; i++)
	{
		if (i==0)			kmSetVertexRenderState (&MV_Scanner[0]);
		if (i==1)			kmSetVertexRenderState (&MV_Scanner[1]);
		if (i==nNumFaces-1) kmSetVertexRenderState (&MV_Scanner[2]);

		/* Strip start */
		kmxxGetCurrentPtr(&BufferDesc);
		kmxxStartVertexStrip(&BufferDesc);
		
		/* Vertices */
		nFace = *(pFaces+nFacesCont++);
		Buffer.fAX = (pVertices+nFace)->fX;
		Buffer.fAY = (pVertices+nFace)->fY;
		Buffer.uA.fAZ = (pVertices+nFace)->u.fZ;
			
		nFace = *(pFaces+nFacesCont++);
		Buffer.fBX = (pVertices+nFace)->fX;
		Buffer.fBY = (pVertices+nFace)->fY;
		Buffer.uB.fBZ = (pVertices+nFace)->u.fZ;

		nFace = *(pFaces+nFacesCont++);
		Buffer.fCX = (pVertices+nFace)->fX;
		Buffer.fCY = (pVertices+nFace)->fY;
		Buffer.uC.fCZ = (pVertices+nFace)->u.fZ;

		kmxxSetVertex_17(KM_VERTEXPARAM_ENDOFSTRIP, 
						Buffer.fAX, Buffer.fAY, Buffer.uA.fAZ, 
						Buffer.fBX, Buffer.fBY, Buffer.uB.fBZ, 
						Buffer.fCX, Buffer.fCY, Buffer.uC.fCZ);

		/* Strip end */
		kmxxReleaseCurrentPtr(&BufferDesc);
	
	}					
}
