/*******************************************************************************
 *	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 stone to knight texture morph 		   *
 *	for the start of the Knight Demo. Involves texture compositing of the 	   *
 *	stone texture of the knight statue with the texture(s) for the living	   *
 *	knight. Includes initialization, drawing and texture compositing, and	   *
 *	clean-up for the knight morph.											   *
 *******************************************************************************/
#include "stdwin.h"
#include "Util.h"
#include "Watchers.h"
#include "DirectDraw.h"
#include "multimedia.h"

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

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

#include "filenames.h"

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

#define REREAD_CAMERA_SCRIPT_ON_SETMODE

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

#define PEDESTAL_MOTION_FILENAME		BASE_PATH "Pedestal.ajm"
#define KNIGHTSTONE_TEXTURE_FILENAME	BASE_PATH "stone.tga"

#define SCRIPT_SPHINCTER_FILENAME		BASE_PATH "morph.scr"
#define SCRIPT_DRAGON_FILENAME			BASE_PATH "morph1.scr"

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

extern BOOL g_blockPaint;

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

static JointMotion*		s_pKnightMotion;
static uint32			s_currentTick = 0;
static uint32			s_knightTick = 0;
static Ati3dTexture*	s_pStoneTexture;
static int				s_stoneLevel = 0;
static Group*			s_pSkull;
static BOOL				s_showSkull;
static Vector			s_skullPosition;
static Vector			s_skullVelocity;
static Vector			s_skullStart;

CameraScript*			g_pCameraScript;

static CameraScript*	s_pCameraScriptDragon;
static CameraScript*	s_pCameraScriptSphincter;
static int				s_ending = 0;

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

void Morph::Cleanup(void) throw(Exception)
{
	if(s_pCameraScriptSphincter)
		delete s_pCameraScriptSphincter;
	s_pCameraScriptSphincter = NULL;

	if(s_pCameraScriptDragon)
		delete s_pCameraScriptDragon;
	s_pCameraScriptDragon = NULL;

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

	delete s_pKnightMotion;
}

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

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

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

	s_pSkull = Pedestal::Object()->FindGroup("Skull01");
	if(!s_pSkull) THROW_EXCEPTION();

	s_skullStart = s_pSkull->Translation();

	s_pCameraScriptSphincter = new CameraScript(SCRIPT_SPHINCTER_FILENAME);
	DECLARE_POINTER_WATCHER(CameraScript*, s_pCameraScriptSphincter, success, s_pCameraScriptSphincter);

	s_pCameraScriptDragon = new CameraScript(SCRIPT_DRAGON_FILENAME);
	DECLARE_POINTER_WATCHER(CameraScript*, s_pCameraScriptDragon, success, s_pCameraScriptDragon);

	success = TRUE;
}

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

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

	EnterCriticalSection(&g_physicsMutex);

	s_ending = 1 - s_ending;

#ifdef REREAD_CAMERA_SCRIPT_ON_SETMODE
	if(s_pCameraScriptDragon)
		delete s_pCameraScriptDragon;
	s_pCameraScriptDragon = NULL;
	s_pCameraScriptDragon = new CameraScript(SCRIPT_DRAGON_FILENAME);
#endif

	if(s_ending == 0)
		g_pCameraScript = s_pCameraScriptSphincter;
	else
		g_pCameraScript = s_pCameraScriptDragon;

	g_pCameraScript->Init();

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

	s_currentTick = 0;
	s_knightTick = 0;
	s_stoneLevel = 0;

	s_showSkull = TRUE;
	s_pSkull->Translation() = s_skullStart;
	s_skullPosition = s_pSkull->Translation();
	s_skullVelocity = Vector(0, 0, 0);

	DoCopy();

	NormalMode::m_pUserDraw = NULL;
	NormalMode::m_pDrawKnight = DrawKnightOverride;

	LeaveCriticalSection(&g_physicsMutex);
}

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

void Morph::Physics(PhysicsType type) throw()
{
	if(type == PHYSICS_COPY)
		DoCopy();
	else
	{
		if(g_pCameraScript)
			g_pCameraScript->Tick();

		if((s_currentTick >= 90) && (s_currentTick <= 120))
			s_stoneLevel = (s_currentTick - 90) * 256 / 30;

		if(s_currentTick > 150)
			s_knightTick++;

		if(s_showSkull)
		{
			s_skullPosition += s_skullVelocity;

			if(s_currentTick == 328)
				s_skullVelocity = Vector(0, -4.0, 4.0);
			if(s_currentTick > 328)
				s_skullVelocity += Vector(0, 0, -0.427);
			if(s_currentTick == 400) s_showSkull = FALSE;
		}

		s_currentTick++;

		NormalMode::Physics(PHYSICS_RUN);

		if(s_knightTick == s_pKnightMotion->TickCount())
		{
			if(s_ending == 0)
				Sphincter::SetMode();
			else
				Dragon::SetMode();

			s_knightTick = 0;
			s_currentTick = 0;
		}
	}
}

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

void Morph::DoCopy(void)
{
	s_pKnightMotion->SetTick(s_knightTick);

	NormalMode::m_knightPosition = Pedestal::Position() + Pedestal::Rotation() * g_pKnight->Translation();
	g_pKnight->Translation() = Vector(ZERO);
	NormalMode::m_knightRotation = Pedestal::Rotation();

	if(s_showSkull)
		s_pSkull->Translation() = s_skullPosition;

	if(g_pCameraScript)
		g_pCameraScript->Copy();

	NormalMode::Physics(PHYSICS_COPY);
	Pedestal::Object()->Latch();
}

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

void Morph::DrawKnightOverride(Clipper& rClipper) throw(Exception)
{
	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);

	if((s_stoneLevel == 0) || (s_stoneLevel == 256))
	{
		g_clipper.Context()->SetTexture((s_stoneLevel==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_stoneLevel / 16);
	}

	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);
}

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