/*---------------------------------------------------------------------------*
  Project:  NitroSystem - build - demos - g3d - demolib
  File:     camera.c

  Copyright 2004,2005 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: camera.c,v $
  Revision 1.6  06/29/2005 04:56:34 AM  hatamoto_minoru
  Corrected the year number given in the copyright.

  Revision 1.5  06/29/2005 04:43:58 AM  hatamoto_minoru
  Fixed typos: NitroSyetem -> NitroSystem

  Revision 1.4  11/12/2004 05:40:32 AM  nishida
  Revised project name of file header.

  Revision 1.3  09/02/2004 07:40:21 AM  nishida_kenji
  change MAX_DISTANCE.

  Revision 1.2  07/21/2004 04:47:04 AM  nishida_kenji
  Opened ABXY key in demo composer.

  Revision 1.1  07/13/2004 11:13:06 AM  nishida
  Registered the initial version.

  $NoKeywords: $
 *---------------------------------------------------------------------------*/

#include "g3d_demolib/system.h"
#include "g3d_demolib/camera.h"

#define	CAMERA_SPEED  		256

#define	MAX_ROTATION		0x3f00				/* 90deg == 0x4000*/
#define	MIN_ROTATION		(-MAX_ROTATION)

#define	MAX_DISTANCE		(150 * FX32_ONE)
#define	MIN_DISTANCE		(  4 * FX32_ONE)


/*---------------------------------------------------------------------------*
  Name:         G3DDemo_InitCamera

  Description:  Initializes Vw3Camera structure.

  Arguments:    camera: pointer to the G3DDemoCamera structure
				posy    : height of fixation point
				distance: distance between fixation point and camera

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
G3DDemo_InitCamera(G3DDemoCamera* camera, fx32 posy, fx32 distance)
{
	camera->persp.fovySin  = FX32_SIN30;
    camera->persp.fovyCos  = FX32_COS30;
    camera->persp.aspect   = FX32_ONE * 4 / 3;
    camera->persp.nearClip = FX32_ONE;
    camera->persp.farClip  = FX32_ONE * 400;

	camera->lookat.target.x	= 0;
	camera->lookat.target.y	= posy;
	camera->lookat.target.z	= 0;

	camera->angleX   = 256 * 20;
	camera->angleY   = 0;
	camera->angleZ   = 0;
	camera->distance = distance;

	G3DDemo_CalcCamera(camera);
}

/*---------------------------------------------------------------------------*
  Name:         G3DDemo_CalcCamera

  Description:  Calculates the LookAt parameter from polar coordinate values.

  Arguments:    camera:	pointer to the G3DDemoCamera structure

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
G3DDemo_CalcCamera(G3DDemoCamera* camera)
{
	G3DDemoLookAt* lookat = &camera->lookat;
	G3DDemoPersp*  persp  = &camera->persp;

	fx16 sinx = FX_SinIdx((u16)camera->angleX);
	fx16 cosx = FX_CosIdx((u16)camera->angleX);
	fx16 siny = FX_SinIdx((u16)camera->angleY);
	fx16 cosy = FX_CosIdx((u16)camera->angleY);
	fx16 sinz = FX_SinIdx((u16)camera->angleZ);
	fx16 cosz = FX_CosIdx((u16)camera->angleZ);

	lookat->camPos.x = cosx * camera->distance >> FX32_SHIFT;
	lookat->camPos.y = sinx * camera->distance >> FX32_SHIFT;
	lookat->camPos.z = cosx * camera->distance >> FX32_SHIFT;

	lookat->camPos.x = lookat->target.x + lookat->camPos.x * siny >> FX32_SHIFT;
	lookat->camPos.y = lookat->target.y + lookat->camPos.y;
	lookat->camPos.z = lookat->target.z + lookat->camPos.z * cosy >> FX32_SHIFT;

    lookat->camUp.x =  FX_Mul( sinz, cosy );
    lookat->camUp.y =  cosz;
    lookat->camUp.z = -FX_Mul( sinz, siny );
}

/*---------------------------------------------------------------------------*
  Name:         G3DDemo_MoveCamera

  Description:  Controls camera with pad. Does not request camera matrix.

  Arguments:    camera:	pointer to the G3DDemoCamera structure

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
G3DDemo_MoveCamera(G3DDemoCamera* camera)
{
  // camera up/down

	if (G3DDEMO_IS_PAD_PRESS(PAD_KEY_UP))
	{
    	if ((camera->angleX += CAMERA_SPEED) > MAX_ROTATION)
    	{
			camera->angleX = MAX_ROTATION;
		}
	}
	if (G3DDEMO_IS_PAD_PRESS(PAD_KEY_DOWN))
	{
		if ((camera->angleX -= CAMERA_SPEED) < MIN_ROTATION)
		{
			camera->angleX = MIN_ROTATION;
		}
	}


  // camera left/right
	if (G3DDEMO_IS_PAD_PRESS(PAD_KEY_LEFT))
	{
		camera->angleY -= CAMERA_SPEED;
	}
	if (G3DDEMO_IS_PAD_PRESS(PAD_KEY_RIGHT))
	{
		camera->angleY += CAMERA_SPEED;
	}
#if 0
  // camera tilt
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_L))
	{
    	if ((camera->angleZ += CAMERA_SPEED) > MAX_ROTATION)
    	{
			camera->angleZ = MAX_ROTATION;
		}
	}
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_R))
	{
		if ((camera->angleZ -= CAMERA_SPEED) < MIN_ROTATION)
		{
			camera->angleZ = MIN_ROTATION;
		}
	}
#endif

	// camera distance
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_L))
	{
		if ((camera->distance += CAMERA_SPEED) > MAX_DISTANCE)
		{
			camera->distance = MAX_DISTANCE;
		}
	}
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_R))
	{
		if ((camera->distance -= CAMERA_SPEED) < MIN_DISTANCE)
		{
			camera->distance = MIN_DISTANCE;
		}
	}

#if 0
	// height of fixation point
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_Y))
	{
		camera->lookat.target.y -= CAMERA_SPEED;
	}
	if (G3DDEMO_IS_PAD_PRESS(PAD_BUTTON_X))
	{
		camera->lookat.target.y += CAMERA_SPEED;
	}
#endif
}

