/*******************************************************************************
 *	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 pedestal the knight stands on to	   *	
 *	begin the demo. Includes initialization, drawing, shading and clean-up for * 	
 *	modeling of the knight's pedestal.										   *
 *******************************************************************************/
#include "stdwin.h"
#include <math.h>
#include <malloc.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 "pedestal.h"
#include "normalmode.h"
#include "shadow.h"

#include "filenames.h"

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

#define PEDESTAL_OBJECT_FILENAME		BASE_PATH "Pedestal.a3d"
#define PEDESTAL_TEXTURE_FILENAME		BASE_PATH "Pedestal.pcx"

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

#define MAX_SHADOW_VERTICES	40
#define MAX_SHADOW_FACES	40

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

Ati3dTexture*		Pedestal::m_pTexture;
Object*				Pedestal::m_pObject;

Normal				Pedestal::m_top;
Vector				Pedestal::m_corner;
Vector				Pedestal::m_vectors[2];

Poly*				Pedestal::m_pShadowPolys[PEDESTAL_MAX_SHADOW_POLYS];
int					Pedestal::m_nShadowPolys;

int						Pedestal::m_shadowVertexCount;
int						Pedestal::m_shadowFaceCount;
Vertex					Pedestal::m_shadowVertices[MAX_SHADOW_VERTICES];
Pedestal::_FaceIndex	Pedestal::m_shadowFacelist[MAX_SHADOW_FACES];

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

Vector Pedestal::m_position = Vector(100, -510.5, -2360);
Matrix Pedestal::m_rotation = Matrix(ROTATION, 0, M_PI/2, 0);
#define PEDESTAL_ROTATION (Pedestal::Rotation() * Matrix(ROTATION, M_PI/2, 0, 0))

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

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

	delete m_pObject;
	m_pObject = NULL;

}

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

	A3DRead(&m_pObject, PEDESTAL_OBJECT_FILENAME);
	DECLARE_POINTER_WATCHER(::Object*, m_pObject, success, object);

	m_pTexture = ATI3DCIF::LoadTexture(*g_pDD, PEDESTAL_TEXTURE_FILENAME, C3D_ETF_RGB1555);
	DECLARE_POINTER_WATCHER(Ati3dTexture*, m_pTexture, success, texture);

	Group* pTop = Object()->FindGroup("Top");
	if(pTop)
	{
		Poly* pPoly = pTop->PolyHead().First()->Object();
		m_top = TransformBy(pPoly->GetFaceNormal(0), PEDESTAL_ROTATION, Position());

		int common[4];
		int nCommon=0;
		int unique[4];
		int nUnique=0;
		int a0 = pPoly->GetFace(0).vertices[0];
		int a1 = pPoly->GetFace(0).vertices[1];
		int a2 = pPoly->GetFace(0).vertices[2];
		int b0 = pPoly->GetFace(1).vertices[0];
		int b1 = pPoly->GetFace(1).vertices[1];
		int b2 = pPoly->GetFace(1).vertices[2];
		if((a0 == b0) || (a0 == b1) || (a0 == b2)) common[nCommon++] = a0; else unique[nUnique++] = a0;
		if((a1 == b0) || (a1 == b1) || (a1 == b2)) common[nCommon++] = a1; else unique[nUnique++] = a1;
		if((a2 == b0) || (a2 == b1) || (a2 == b2)) common[nCommon++] = a2; else unique[nUnique++] = a2;
		if((b0 != a0) && (b0 != a1) && (b0 != a2)) unique[nUnique++] = b0;
		else if((b1 != a0) && (b1 != a1) && (b1 != a2)) unique[nUnique++] = b1;
		else if((b2 != a0) && (b2 != a1) && (b2 != a2)) unique[nUnique++] = b2;

		ASSERT(nCommon == 2);
		ASSERT(nUnique == 2);

		m_corner = TransformBy(pPoly->GetVertex(common[0]).XYZ(), PEDESTAL_ROTATION, Position());
		m_vectors[0] = TransformBy(pPoly->GetVertex(unique[0]).XYZ(), PEDESTAL_ROTATION, Position()) - Corner();
		m_vectors[1] = TransformBy(pPoly->GetVertex(unique[1]).XYZ(), PEDESTAL_ROTATION, Position()) - Corner();
	}
	else
	{
		TRACE("ERROR: Pedestal Top Not Found\n");
		THROW_EXCEPTION();
	}

	Object()->Latch();
	PrecastShadow();

	success = TRUE;
}

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

void Pedestal::Draw(Clipper& rClipper)
{
	rClipper.Stack()->TransformObject(PEDESTAL_ROTATION, Position());

	rClipper.Context()->SetTexture(Texture());
	Object()->Draw(g_clipper, VERTEXTYPE_TC);

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



void Pedestal::DrawShadow(Clipper& rClipper)
{
	for(int i=0; i<m_nShadowPolys; i++)
		g_clipper.DrawPolygon(*m_pShadowPolys[i], VERTEXTYPE_1);
}

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

void Pedestal::PrecastCallback(const Poly& rPoly, const Normal& rNormal, const BOOL* const pDrawFace, const BOOL* const pDrawVertex, const Vertex* const pVertices)
{
	ASSERT(m_nShadowPolys < PEDESTAL_MAX_SHADOW_POLYS);

	int faceCount = 0;
	for(int i=0; i<rPoly.FaceCount(); i++) if(pDrawFace[i]) faceCount++;

	int vertexCount = 0;
	for(i=0; i<rPoly.VertexCount(); i++) if(pDrawVertex[i]) vertexCount++;

	Poly* pPoly = new Poly(rPoly.Type(), vertexCount, faceCount);
	m_pShadowPolys[m_nShadowPolys] = pPoly;
	m_nShadowPolys++;

	faceCount = 0;
	for(i=0; i<rPoly.FaceCount(); i++)
		if(pDrawFace[i])
		{
			const PolyFace* pFaceSrc = &rPoly.GetFace(i);
			PolyFace* pFaceDst = &pPoly->GetFace(faceCount);
			pFaceDst->normal = TransformBy(rNormal, PEDESTAL_ROTATION, Position());
			pFaceDst->vertices[0] = pFaceSrc->vertices[0];
			pFaceDst->vertices[1] = pFaceSrc->vertices[1];
			pFaceDst->vertices[2] = pFaceSrc->vertices[2];
			faceCount++;
		}

	vertexCount = 0;
	for(i=0; i<rPoly.VertexCount(); i++)
		if(pDrawVertex[i])
		{
			pPoly->GetVertex(vertexCount) = Vertex(TransformBy(pVertices[i].XYZ(), PEDESTAL_ROTATION, Position()));

			for(int j=0; j<pPoly->FaceCount(); j++)
			{
				if(pPoly->GetFace(j).vertices[0] == i) pPoly->GetFace(j).vertices[0] = vertexCount;
				if(pPoly->GetFace(j).vertices[1] == i) pPoly->GetFace(j).vertices[1] = vertexCount;
				if(pPoly->GetFace(j).vertices[2] == i) pPoly->GetFace(j).vertices[2] = vertexCount;
			}

			vertexCount++;
		}
}

void Pedestal::PrecastShadow(void)
{
	g_gfxStack.ObjectLight() = g_sunPosition;

//	LandSquare* pSquare = &g_landscape.SquareAt(Position().X(), Position().Z());
	Normal nWorld = Normal(0, -1, 0, -470);
	Normal nObject = UntransformBy(nWorld, PEDESTAL_ROTATION, Position());

	g_gfxStack.TransformObject(PEDESTAL_ROTATION, Position());

	m_nShadowPolys = 0;
	m_shadowVertexCount = 0;
	m_shadowFaceCount = 0;
	Shadow::DropCustom(*Object(), nObject, PrecastCallback);

	g_gfxStack.TransformDone();
}

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

int Pedestal::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 Pedestal::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++;
}

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

