/*******************************************************************************
 *	ATI 3D RAGE SDK sample code												   *	
 *																			   *
 *  Knight Demo																   *
 *																			   *
 *  Copyright (c) 1996-1997 ATI Technologies, Inc.  All rights reserved.	   *	
 *																			   *
 * Written by Aaron Orenstein												   *
 *  																		   *
 *	The base sequence and set up for the Knight Demo dragon. Includes		   *
 *	initialization,	drawing, alpha-blending (for dragon's wings) and clean-up  *
 *	for modeling of the dragon.												   *
 *******************************************************************************/
#include "stdwin.h"
#include "Util.h"
#include "Watchers.h"
#include "DirectDraw.h"
#include "multimedia.h"

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

#include "normalmode.h"
#include "morph.h"
#include "pedestal.h"
#include "dragon.h"

#include "filenames.h"
#include "shadow.h"

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

#define DRAGON_OBJECT_FILENAME		BASE_PATH "dragon.a3d"
#define DRAGON_TEXTURE_FILENAME		BASE_PATH "dragon.tga"
#define DRAGON_MOTION_FILENAME		BASE_PATH "dragon.ajm"
#define KNIGHT_THREATEN_FILENAME	BASE_PATH "crouch.ajm"

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

Vector	Dragon::m_position = Vector(-435, -508, -2855);
Matrix	Dragon::m_rotation = Matrix(ROTATION, M_PI/2.0, 0, M_PI/2.0);

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

extern BOOL g_blockPaint;

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

static uint32			s_currentTick;

static Vector			s_cameraPosition = Vector(0, -6*12, 6*12);
static Matrix			s_cameraRotation = Matrix(ROTATION, DEG2RAD(5), M_PI, 0);

static Vector			s_position(ZERO);
static Matrix			s_rotation(IDENTITY);
static BOOL				s_setRotation;

static Object*			s_pDragon;
static Ati3dTexture*	s_pDragonTexture;
static JointMotion*		s_pDragonMotion;

static uint32			s_dragonTick;

static FlightData		s_flightData;
static float			s_scale = 1.0;

static Vector			s_knightDist;

static JointMotion*		s_pKnightMotion;

static uint32			s_dragonStart = 0;

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

void Dragon::Cleanup(void) throw(Exception)
{
	delete s_pKnightMotion;
	s_pKnightMotion = NULL;

	delete s_pDragonMotion;
	s_pDragonMotion = NULL;

	delete s_pDragonTexture;
	s_pDragonTexture = NULL;

	delete s_pDragon;
	s_pDragon = NULL;
}

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

	A3DRead(&s_pDragon, DRAGON_OBJECT_FILENAME);
	DECLARE_POINTER_WATCHER(Object*, s_pDragon, success, s_pDragon);

	s_pDragonTexture = ATI3DCIF::LoadTexture(*g_pDD, DRAGON_TEXTURE_FILENAME, C3D_ETF_RGB4444);
	DECLARE_POINTER_WATCHER(Ati3dTexture*, s_pDragonTexture, success, s_pDragonTexture);

	s_pDragonMotion = JointMotion::Read(DRAGON_MOTION_FILENAME, s_pDragon);
	DECLARE_POINTER_WATCHER(JointMotion*, s_pDragonMotion, success, s_pDragonMotion);

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

	success = TRUE;
}

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

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

	EnterCriticalSection(&g_physicsMutex);

	NormalMode::SetMode();

	s_currentTick = 0;
	s_cameraPosition = Vector(0, -6*12, 6*12);
	s_cameraRotation = Matrix(ROTATION, DEG2RAD(5), M_PI, 0);

	s_position = Pedestal::Position();
	s_rotation = Pedestal::Rotation();

	s_pDragonMotion->SetTick(0);
	s_dragonTick = 0;

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

	LeaveCriticalSection(&g_physicsMutex);
}

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

static void DragonDraw(Clipper& rClipper)
{
	rClipper.Stack()->TransformObject(Dragon::Rotation(), Dragon::Position());

	rClipper.Context()->SetTexture(s_pDragonTexture);
	rClipper.Context()->SetAlphaDst(C3D_EADST_SRCALPHA);
	rClipper.Context()->SetAlphaSrc(C3D_EASRC_INVSRCALPHA);
	rClipper.Context()->SetTextureOp(C3D_ETEXOP_ALPHA);

	s_pDragon->Draw(rClipper, VERTEXTYPE_TC);

	rClipper.Context()->SetAlphaDst(C3D_EADST_ZERO);
	rClipper.Context()->SetAlphaSrc(C3D_EASRC_ONE);
	rClipper.Context()->SetTextureOp(C3D_ETEXOP_NONE);

	rClipper.Stack()->TransformDone();
}

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

void Dragon::Physics(PhysicsType type) throw()
{
	if(type == PHYSICS_COPY)
	{
		if(s_currentTick < s_pKnightMotion->TickCount())
			s_pKnightMotion->SetTick(s_currentTick);
		else
			s_pKnightMotion->SetTick(s_pKnightMotion->TickCount()-1);

		NormalMode::m_knightPosition = s_position + s_rotation * g_pKnight->Translation();
		g_pKnight->Translation() = Vector(ZERO);

		if(s_currentTick >= s_dragonStart)
		{
			if(s_currentTick - s_dragonStart < s_pDragonMotion->TickCount())
				s_pDragonMotion->SetTick(s_currentTick - s_dragonStart);
			else
				s_pDragonMotion->SetTick(s_pDragonMotion->TickCount()-1);
		}
		else
			s_pDragonMotion->SetTick(0);

		if(g_pCameraScript)
			g_pCameraScript->Copy();

		NormalMode::Physics(PHYSICS_COPY);
		s_pDragon->Latch();

		NormalMode::m_pUserDraw = DragonDraw;
	}
	else
	{
		if(g_pCameraScript)
			g_pCameraScript->Tick();

		s_currentTick++;
		if(s_currentTick == s_pKnightMotion->TickCount()+120)
			Morph::SetMode();
	}
}

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