/*******************************************************************************
 *	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 castle. Includes		   *	
 *	initialization,	drawing, shading and clean-up for modeling of castle.	   *
 *******************************************************************************/
#include "stdwin.h"
#include <math.h>
#include "Util.h"
#include "Watchers.h"
#include "DirectDraw.h"

#include "Ati3dCIFx.h"
#include "Matrix.h"
#include "Multimedia.h"

#include "AtiDemoWnd.h"
#include "AtiDemo.h"
#include "Polygon.h"
#include "a3d.h"
#include "castle.h"
#include "normalmode.h"
#include "shadow.h"

#include "filenames.h"

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

#define BODIAM_OBJECT_FILENAME			BASE_PATH "castleF.a3d"
#define BODIAM_LEFT_OBJECT_FILENAME		BASE_PATH "castleL.a3d"
#define BODIAM_RIGHT_OBJECT_FILENAME	BASE_PATH "castleR.a3d"
#define BODIAM_TEXTURE_FILENAME			BASE_PATH "castle.pcx"

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

#define MAX_SHADOW_VERTICES	300
#define MAX_SHADOW_FACES	100

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

int					Castle::m_shadowVertexCount;
int					Castle::m_shadowFaceCount;
Vertex				Castle::m_shadowVertices[MAX_SHADOW_VERTICES];
TLVertex			Castle::m_shadowTLVertices[MAX_SHADOW_VERTICES];
Castle::_FaceIndex	Castle::m_shadowFacelist[MAX_SHADOW_FACES];

Object*				Castle::m_pCastle;
Object*				Castle::m_pSideL;
Object*				Castle::m_pSideR;
Ati3dTexture*		Castle::m_pTexture;

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

Vector Castle::m_position = Vector(-108, -438, -2506);
Matrix Castle::m_rotation = Matrix(ROTATION, Vector(M_PI/2, 0, M_PI));

static Vertex s_wallHack[4];
static Normal s_wallHackNormal;

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

void Castle::Cleanup(void)
{
	delete m_pTexture;
	m_pTexture = NULL;

	delete m_pSideR;
	m_pSideR = NULL;

	delete m_pSideL;
	m_pSideL = NULL;

	delete m_pCastle;
	m_pCastle = NULL;
}

void Castle::Initialize(void)
{
	BOOL success = FALSE;

	A3DRead(&m_pSideL, BODIAM_LEFT_OBJECT_FILENAME);
	DECLARE_POINTER_WATCHER(Object*, m_pSideL, success, left_object);

	A3DRead(&m_pSideR, BODIAM_RIGHT_OBJECT_FILENAME);
	DECLARE_POINTER_WATCHER(Object*, m_pSideR, success, right_object);

	A3DRead(&m_pCastle, BODIAM_OBJECT_FILENAME);
	DECLARE_POINTER_WATCHER(Object*, m_pCastle, success, castle_object);

	m_pTexture = ATI3DCIF::LoadTexture(*g_pDD, BODIAM_TEXTURE_FILENAME, C3D_ETF_RGB332);
	DECLARE_POINTER_WATCHER(Ati3dTexture*, m_pTexture, success, bodiamB);

	m_pCastle->Latch();
	m_pSideL->Latch();
	m_pSideR->Latch();

	PrecastShadow();

	success = TRUE;
}

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

void Castle::Draw(Clipper& rClipper)
{
	g_gfxStack.TransformObject(Rotation(), Position());

	rClipper.Context()->SetTexture(m_pTexture);
	m_pCastle->Draw(g_clipper, VERTEXTYPE_TC);
	g_clipper.DrawQuad(s_wallHack[0], s_wallHack[1], s_wallHack[2], s_wallHack[3], VERTEXTYPE_TC);

	rClipper.Stack()->TransformObject(Matrix(ROTATION, Vector(0, 0, -M_PI/2.0)), Vector(-996, 424, 21));
	m_pSideL->Draw(g_clipper, VERTEXTYPE_TC);
	rClipper.Stack()->TransformDone();

	rClipper.Stack()->TransformObject(Matrix(ROTATION, Vector(0, 0, M_PI/2.0)), Vector(1200, 200, 21));
	m_pSideR->Draw(g_clipper, VERTEXTYPE_TC);
	rClipper.Stack()->TransformDone();

	for(int j=0; j<7; j++)
	{
		int dx = j*269;
		Vertex v0a(Vector(-840+dx, 1000, 157), Normal(0, -1, 0, 1000), UV( 79.0/255.0, 180.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v1a(Vector(-571+dx, 1000, 157), Normal(0, -1, 0, 1000), UV(232.0/255.0, 180.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v2a(Vector(-571+dx, 1000,  21), Normal(0, -1, 0, 1000), UV(232.0/255.0, 254.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v3a(Vector(-840+dx, 1000,  21), Normal(0, -1, 0, 1000), UV( 79.0/255.0, 254.0/255.0), RGBA(255, 255, 255, 255));
		g_clipper.DrawQuad(v0a, v1a, v2a, v3a, VERTEXTYPE_TC);

		Vertex v0b(Vector(-840+dx, 1000, 284), Normal(0, -1, 0, 1000), UV( 79.0/255.0, 180.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v1b(Vector(-571+dx, 1000, 284), Normal(0, -1, 0, 1000), UV(232.0/255.0, 180.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v2b(Vector(-571+dx, 1000, 157), Normal(0, -1, 0, 1000), UV(232.0/255.0, 226.0/255.0), RGBA(255, 255, 255, 255));
		Vertex v3b(Vector(-840+dx, 1000, 157), Normal(0, -1, 0, 1000), UV( 79.0/255.0, 226.0/255.0), RGBA(255, 255, 255, 255));
		g_clipper.DrawQuad(v0b, v1b, v2b, v3b, VERTEXTYPE_TC);
	}

	g_gfxStack.TransformDone();
}

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

void Castle::DrawShadow(Clipper& rClipper)
{
	for(int i=0; i<m_shadowVertexCount; i++)
		rClipper.Stack()->TransformPoint(&m_shadowTLVertices[i], &m_shadowVertices[i], VERTEXTYPE_1);

	for(i=0; i<m_shadowFaceCount; i++)
		g_clipper.DrawTriangle(m_shadowTLVertices[m_shadowFacelist[i].v0],
							   m_shadowTLVertices[m_shadowFacelist[i].v1],
							   m_shadowTLVertices[m_shadowFacelist[i].v2],
							   VERTEXTYPE_1);
}

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

#define CORRIDOR_POINT_0	Vector(180, -11.811534, reference.Z())
#define CORRIDOR_POINT_1	Vector(180, -11.811534, 126)
#define CORRIDOR_POINT_2	Vector(162, -11.811534, 162)
#define CORRIDOR_POINT_3	Vector(138, -11.811534, 180)
#define CORRIDOR_POINT_4	Vector(102, -11.811534, 180)
#define CORRIDOR_POINT_5	Vector(78, -11.811534, 162)
#define CORRIDOR_POINT_6	Vector(60, -11.811534, 126)


void Castle::PrecastShadow(void)
{
	m_shadowVertexCount = 0;
	m_shadowFaceCount = 0;

	g_gfxStack.ObjectLight() = g_sunPosition;

	Vector pt = TransformBy(Vector(180, -11.811534, 0), Rotation(), Position());
	//LandSquare* pSquare = &g_landscape.SquareAt(pt.X(), pt.Z());
	Normal nWorld = Normal(0, -1, 0, -470);
	Normal nFloor = UntransformBy(nWorld, Rotation(), Position());

	g_gfxStack.TransformObject(Rotation(), Position());
	Vector light = g_gfxStack.ObjectLight();
	g_gfxStack.TransformDone();

	Vector reference = UntransformBy(Vector(-635.294, -470, -2752), Rotation(), Position());

	Vector floor[12];
	floor[0] =  floor[1] = CORRIDOR_POINT_0;
	floor[2] =  floor[3] = Shadow::Project(nFloor, CORRIDOR_POINT_1, light);
	floor[4] =  floor[5] = Shadow::Project(nFloor, CORRIDOR_POINT_2, light);
	floor[6] =  floor[7] = Shadow::Project(nFloor, CORRIDOR_POINT_3, light);
	floor[8] =  floor[9] = Shadow::Project(nFloor, CORRIDOR_POINT_4, light);
	floor[10] =  floor[11] = Shadow::Project(nFloor, CORRIDOR_POINT_5, light);

	floor[0].X()++;	// HACK: Get rid of some see-through
	floor[1].X()++;

	Vector postTrans[12];
	for(int i=0; i<10; i++)
	{
		if(i&1) floor[i].Y() = 163;
		postTrans[i] = TransformBy(floor[i], Rotation(), Position());
	}

	for(i=0; i<8; i++)
		AddShadowFace(postTrans[i+0], postTrans[i+1], postTrans[i+2]);

	Normal nWall = Normal(-1, 0, 0, 60);

	Vector wall[10];
	wall[0] = wall[1] = Shadow::Project(nWall, floor[6], floor[8]);
	wall[2] = wall[3] = Shadow::Project(nWall, CORRIDOR_POINT_4, light);
	wall[4] = wall[5] = Shadow::Project(nWall, CORRIDOR_POINT_5, light);
	wall[6] = wall[7] = CORRIDOR_POINT_6;

	for(i=0; i<8; i++)
	{
		wall[i].X()+=0.25;	// Hmmm... More hack...
		if(i&1) wall[i].Y() = 163;
		postTrans[i] = TransformBy(wall[i], Rotation(), Position());
	}

	for(i=0; i<6; i++)
		AddShadowFace(postTrans[i+0], postTrans[i+1], postTrans[i+2]);

	Group* pCorridor = m_pCastle->FindGroup("Corridor");
	if(pCorridor)
	{
		Poly* pPoly = pCorridor->PolyHead().First()->Object();

		s_wallHack[0] = pPoly->GetFaceVertex(0, 0);
		s_wallHack[1] = pPoly->GetFaceVertex(0, 1);
		s_wallHack[2] = pPoly->GetFaceVertex(0, 2);
		s_wallHack[3] = pPoly->GetFaceVertex(1, 2);
		s_wallHackNormal = pPoly->GetFaceNormal(0);

		s_wallHack[0].Normal() = Normal(0, 0, 0, 1);
		s_wallHack[1].Normal() = Normal(0, 0, 0, 1);
		s_wallHack[2].Normal() = Normal(0, 0, 0, 1);
		s_wallHack[3].Normal() = Normal(0, 0, 0, 1);

		pPoly->GetFaceNormal(0) = Normal(0, 0, 0, 0); // Never show this one

		// Hack all vertices to be in full shadow
		for(int i=0; i<pPoly->VertexCount(); i++)
			pPoly->GetVertex(i).Normal() = Normal(0, 0, 0, 0);
	}
	else
		TRACE("WARNING: Corridor object not found!\n");

	// Outline in courtyard
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(1212, 282, 564), light),
					   Vector(1212, 282, reference.Z()),
					   Vector(1002, 282, reference.Z()),
					   Shadow::Project(nFloor, Vector(1002, 282, 564), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(1002, 282, 564), light),
					   Vector(1002, 282, reference.Z()),
					   Vector(936, 162, reference.Z()),
					   Shadow::Project(nFloor, Vector(936, 162, 564), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(936, 162, 224), light),
					   Vector(936, 162, reference.Z()),
					   Vector(486, 162, reference.Z()),
					   Shadow::Project(nFloor, Vector(486, 162, 224), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(486, 162, /*522*/224), light),
					   Vector(486, 162, reference.Z()),
					   Vector(-246, 162, reference.Z()),
					   Shadow::Project(nFloor, Vector(-246, 162, /*522*/224), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(-246, 162, 224), light),
					   Vector(-246, 162, reference.Z()),
					   Vector(-696, 162, reference.Z()),
					   Shadow::Project(nFloor, Vector(-696, 162, 224), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(-696, 162, 564), light),
					   Vector(-696, 162, reference.Z()),
					   Vector(-762, 282, reference.Z()),
					   Shadow::Project(nFloor, Vector(-762, 282, 564), light),
					   Rotation(), Position());
	AddShadowTransQuad(Shadow::Project(nFloor, Vector(-762, 282, 564), light),
					   Vector(-762, 282, reference.Z()),
					   Vector(-972, 282, reference.Z()),
					   Shadow::Project(nFloor, Vector(-972, 282, 564), light),
					   Rotation(), Position());

	// Front outlines
	Vector proj = Shadow::Project(Normal(0, 1, 0, 12), Vector(240, -90, 522), light);
	AddShadowTransQuad(proj,
					   Vector(proj.X(), proj.Y(), reference.Z()),
					   Vector(240, -12, reference.Z()),
					   Vector(240, -12, proj.Z()),
					   Rotation(), Position());
	AddShadowTransTri(Vector(proj.X(), proj.Y(), reference.Z()),
					  Vector(240, -12, reference.Z()),
					  Vector(240, -90, reference.Z()),
					  Rotation(), Position());

	proj = Shadow::Project(Normal(0, 1, 0, 24), Vector(-132, -90, 522), light);
	AddShadowTransQuad(proj,
					   Vector(proj.X(), proj.Y(), reference.Z()),
					   Vector(-132, -24, reference.Z()),
					   Vector(-132, -24, proj.Z()),
					   Rotation(), Position());
	AddShadowTransTri(Vector(proj.X(), proj.Y(), reference.Z()),
					  Vector(-132, -24, reference.Z()),
					  Vector(-132, -90, reference.Z()),
					  Rotation(), Position());

	proj = Shadow::Project(Normal(0, 1, 0, -90), Vector(-246, -24, 522), light);
	AddShadowTransQuad(Vector(proj.X(), proj.Y(), 300),
					   Vector(proj.X(), proj.Y(), reference.Z()),
					   Vector(-246, 90, reference.Z()),
					   Vector(-246, 90, 300),
					   Rotation(), Position());
	AddShadowTransTri(Vector(proj.X(), proj.Y(), reference.Z()),
					  Vector(-246, 90, reference.Z()),
					  Vector(-246, -24, reference.Z()),
					  Rotation(), Position());

}

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

int Castle::AddShadowVertex(const Vector& v)
{
	for(int i=0; i<m_shadowVertexCount; i++)
		if(m_shadowVertices[i].XYZ() == v)
			return i;
	ASSERT(m_shadowVertexCount < MAX_SHADOW_VERTICES);
	m_shadowVertices[m_shadowVertexCount].XYZ() = v;
	return m_shadowVertexCount++;
}



void Castle::AddShadowFace(int a, int b, int c)
{
	ASSERT(m_shadowFaceCount < MAX_SHADOW_FACES);
	m_shadowFacelist[m_shadowFaceCount].v0 = a;
	m_shadowFacelist[m_shadowFaceCount].v1 = b;
	m_shadowFacelist[m_shadowFaceCount].v2 = c;
	m_shadowFaceCount++;
}



void Castle::AddShadowFace(const Vector& a, const Vector& b, const Vector& c)
{
	int aIndex = AddShadowVertex(a);
	int bIndex = AddShadowVertex(b);
	int cIndex = AddShadowVertex(c);
	AddShadowFace(aIndex, bIndex, cIndex);
}



void Castle::AddShadowQuad(const Vector& a, const Vector& b, const Vector& c, const Vector& d)
{
	AddShadowFace(a, b, c);
	AddShadowFace(a, c, d);
}



void Castle::AddShadowTransQuad(const Vector& a, const Vector& b, const Vector& c, const Vector& d, const Matrix& rot, const Vector& trans)
{
	AddShadowQuad(TransformBy(a, rot, trans),
				  TransformBy(b, rot, trans),
				  TransformBy(c, rot, trans),
				  TransformBy(d, rot, trans));
}



void Castle::AddShadowTransTri(const Vector& a, const Vector& b, const Vector& c, const Matrix& rot, const Vector& trans)
{
	AddShadowFace(TransformBy(a, rot, trans),
				  TransformBy(b, rot, trans),
				  TransformBy(c, rot, trans));
}

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

