/*******************************************************************************
 *	ATI 3D RAGE SDK sample code												   *	
 *																			   *
 *  Knight Demo																   *
 *																			   *
 *  Copyright (c) 1996-1997 ATI Technologies, Inc.  All rights reserved.	   *	
 *  																		   *
 * Written by Aaron Orenstein												   *
 *																			   *
 *******************************************************************************/
#include "stdwin.h"
#include "Util.h"
#include "Watchers.h"
#include "DirectDraw.h"

#include "AtiDemo.h"
#include "AtiDemoWnd.h"
#include "physics.h"
#include "a3d.h"
#include "ajm.h"

#include "normalmode.h"
#include "knight.h"
#include "multimedia.h"
#include "shadow.h"

#include "filenames.h"

// -----------------------------------------------------------------------------

extern BOOL g_blockPaint;

// -----------------------------------------------------------------------------

#define KNIGHT_CYCLE_FILENAME	BASE_PATH "knitecyc.ajm"
#define KNIGHTSTONE_TEXTURE_FILENAME	BASE_PATH "stone.tga"

// -----------------------------------------------------------------------------

static uint32			s_currentTick;
static JointMotion*		s_pKnightMotion;
static Ati3dTexture*	s_pStoneTexture;
static float			s_stoneLevel = 0;
static float			s_stoneSpeed = 1;
static int				s_stoneLevelCopy;

static float			s_cameraAngle = 0;
static float			s_cameraHeight = 0;
static float			s_cameraDistance = 7*12;

static BOOL				s_doMotion = TRUE;
static BOOL				s_doFade = TRUE;

// -----------------------------------------------------------------------------

void Knight::Cleanup(void) throw(Exception)
{
	delete s_pKnightMotion;

	if(s_pStoneTexture)
	{
		delete s_pStoneTexture;
		s_pStoneTexture = NULL;
	}
}

void Knight::Initialize(void) throw(Exception)
{
	BOOL success = FALSE;

	s_pStoneTexture = ATI3DCIF::LoadTexture(*g_pDD, KNIGHTSTONE_TEXTURE_FILENAME, C3D_ETF_RGB4444);
	DECLARE_POINTER_WATCHER(Ati3dTexture*, s_pStoneTexture, success, sky0b);

	s_pKnightMotion = JointMotion::Read(KNIGHT_CYCLE_FILENAME, g_pKnight);
	DECLARE_POINTER_WATCHER(JointMotion*, s_pKnightMotion, success, s_pKnightMotion);

	success = TRUE;
}

// -----------------------------------------------------------------------------

void Knight::SetMode(void)
{
	TRACE("Knight::SetMode()\n");

	EnterCriticalSection(&g_physicsMutex);

	NormalMode::SetMode();

	g_physics.SetPhysicsMode(Physics);
	g_pWindow->SetKeyPressHandler(KeyPressHandler);

	NormalMode::m_knightPosition = Vector(0, 0, 0);
	NormalMode::m_knightRotation = Matrix(IDENTITY);

	s_currentTick = 0;

	s_stoneLevel = 0;
	s_stoneSpeed = 1.0;

	LeaveCriticalSection(&g_physicsMutex);
}

// -----------------------------------------------------------------------------

void Knight::KeyPressHandler(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	switch(nChar)
	{
	case 'R': SetMode(); break;
	case 'F': s_doFade = !s_doFade; break;
	case 'M': s_doMotion = !s_doMotion; break;
	}
}

// -----------------------------------------------------------------------------

void Knight::Draw(Clipper& rClipper)
{
	g_clipper.Context()->SetZMode(C3D_EZMODE_TESTON_WRITEZ, C3D_EZCMP_LEQUAL);
	g_clipper.Context()->SetAlphaDst(C3D_EADST_SRCALPHA);
	g_clipper.Context()->SetAlphaSrc(C3D_EASRC_INVSRCALPHA);
	g_clipper.Context()->SetTextureOp(C3D_ETEXOP_ALPHA);

	ASSERT((s_stoneLevelCopy >= 0) && (s_stoneLevelCopy <= 16));

	if((s_stoneLevelCopy == 0) || (s_stoneLevelCopy == 16))
	{
		g_clipper.Context()->SetTexture((s_stoneLevelCopy==0)?s_pStoneTexture:g_pKnightTexture);
		g_clipper.Context()->SetCompositeTexture(NULL);
	}
	else
	{
		g_clipper.Context()->SetCompositeTexture(g_pKnightTexture);
		g_clipper.Context()->SetTexture(s_pStoneTexture);
		g_clipper.Context()->SetCompositeFilter(C3D_ETFILT_MIN2BY2_MAG2BY2);
		g_clipper.Context()->SetCompositeFunction(C3D_ETEXCOMPFCN_BLEND);
		g_clipper.Context()->SetCompositeFactor(s_stoneLevelCopy);
	}

	g_pKnight->Draw(g_clipper, VERTEXTYPE_TC);

	g_clipper.Context()->SetCompositeTexture(NULL);
	g_clipper.Context()->SetAlphaDst(C3D_EADST_ZERO);
	g_clipper.Context()->SetAlphaSrc(C3D_EASRC_ONE);
	g_clipper.Context()->SetTextureOp(C3D_ETEXOP_NONE);
}



void Knight::DrawShadow(Clipper& rClipper)
{
	Normal nSurface = Normal(0, -1, 0, 0);
	Normal nObject = UntransformBy(nSurface, NormalMode::m_knightRotation, NormalMode::m_knightPosition);

	g_gfxStack.TransformObject(NormalMode::m_knightRotation, NormalMode::m_knightPosition);

	Shadow::Drop(*g_pKnight, nObject);

	g_gfxStack.TransformDone();
}

// -----------------------------------------------------------------------------

void Knight::Physics(PhysicsType type) throw()
{
	if(type == PHYSICS_COPY)
	{
		s_pKnightMotion->SetTick(s_currentTick);

		NormalMode::m_cameraRotation = Matrix(ROTATION, 0, -s_cameraAngle, 0) * Matrix(ROTATION, -s_cameraHeight, 0, 0);
		NormalMode::m_cameraPosition = NormalMode::m_cameraRotation * Vector(0, 0, -s_cameraDistance) + Vector(0, -72, 0);

		if(NormalMode::m_cameraPosition.Y() > -1) NormalMode::m_cameraPosition.Y() = -1;

		NormalMode::Physics(PHYSICS_COPY);

		s_stoneLevelCopy = (int)(s_stoneLevel + 0.5);
		if(s_stoneLevelCopy > 16) s_stoneLevelCopy = 16;
	}
	else
	{
		if(s_doMotion)
			s_currentTick++;

		s_cameraAngle += Multimedia::JoyTranslation(0).X() / 10.0;
		s_cameraHeight -= Multimedia::JoyTranslation(0).Y() / 10.0;

		if(Multimedia::JoyButtons(0) & 1) s_cameraDistance -= 2;
		if(Multimedia::JoyButtons(0) & 2) s_cameraDistance += 2;

		if(s_cameraDistance < 2*12) s_cameraDistance = 2*12;
		if(s_cameraHeight > 1.57) s_cameraHeight = 1.57;
		if(s_cameraHeight < -1) s_cameraHeight = -1;

		if(s_currentTick == s_pKnightMotion->TickCount())
			s_currentTick = 0;

		static DWORD oldButtons = 0;
		DWORD newButtons = Multimedia::JoyButtons(0);
		DWORD pressed = (newButtons ^ oldButtons) & newButtons;
		oldButtons = newButtons;

		if(pressed & 4) s_stoneSpeed *= 2.0;
		if(pressed & 8) s_stoneSpeed /= 2.0;

		if(s_stoneSpeed > 1) s_stoneSpeed = 1;

		if(s_doFade)
			s_stoneLevel += s_stoneSpeed;

		if(s_stoneLevel <= 0)
		{
			s_stoneLevel = 0;
			s_stoneSpeed = abs(s_stoneSpeed);
		}
		
		if(s_stoneLevel >= 17)
		{
			s_stoneLevel = 17;
			s_stoneSpeed = -abs(s_stoneSpeed);
		}
	}
}

// -----------------------------------------------------------------------------
