/*******************************************************************************
 *	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 rendering of the sky polygon.			   *
 *******************************************************************************/
#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 "physics.h"
#include "normalmode.h"
#include "a3d.h"
#include "ajm.h"
#include "sky.h"

#include "filenames.h"

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

#define DAYSKY_TEXTURE_FILENAME			BASE_PATH "sky.pcx"

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

#define SKY_SIZE	(1000 * 3 * 12)
#define SKY_HEIGHT0	(250 * 12)
#define SKY_HEIGHT1	(-300 * 3 * 12)
#define SKY_HEIGHT2	(-900 * 3 * 12)

#define SKYCOLOR RGBA(82, 132, 173, 0)

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

static Ati3dTexture* s_pSkyTexture;

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

void Sky::Cleanup(void)
{
	delete s_pSkyTexture;
	s_pSkyTexture = NULL;
}

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

	s_pSkyTexture = ATI3DCIF::LoadTexture(*g_pDD, DAYSKY_TEXTURE_FILENAME);
	DECLARE_POINTER_WATCHER(Ati3dTexture*, s_pSkyTexture, success, sky0b);

	success = TRUE;
}

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

#define SKY0 (-0.500 * SKY_SIZE)
#define SKY1 (-0.212 * SKY_SIZE)
#define SKY2 ( 0.212 * SKY_SIZE)
#define SKY3 ( 0.500 * SKY_SIZE)

struct _SkyPolyDef {
	_SkyPolyDef(const Vertex& ia, const Vertex& ib, const Vertex& ic) : count(3),
																		a(ia),
																		b(ib),
																		c(ic),
																		d(ZERO),
																		normal(ia.XYZ(), ib.XYZ(), ic.XYZ())
	{
	}

	_SkyPolyDef(const Vertex& ia, const Vertex& ib, const Vertex& ic, const Vertex& id) :
																		count(4),
																		a(ia),
																		b(ib),
																		c(ic),
																		d(id),
																		normal(ia.XYZ(), ib.XYZ(), ic.XYZ())
	{
	}

	int		count;
	Vertex	a;
	Vertex	b;
	Vertex	c;
	Vertex	d;
	Normal	normal;
};

#define SKYPOLYS_COUNT (sizeof(skyPolys) / sizeof(_SkyPolyDef))

#define SKYA0	Vector(SKY2, SKY_HEIGHT0, SKY0)
#define SKYA1	Vector(SKY3, SKY_HEIGHT0, SKY1)
#define SKYA2	Vector(SKY3, SKY_HEIGHT0, SKY2)
#define SKYA3	Vector(SKY2, SKY_HEIGHT0, SKY3)
#define SKYA4	Vector(SKY1, SKY_HEIGHT0, SKY3)
#define SKYA5	Vector(SKY0, SKY_HEIGHT0, SKY2)
#define SKYA6	Vector(SKY0, SKY_HEIGHT0, SKY1)
#define SKYA7	Vector(SKY1, SKY_HEIGHT0, SKY0)
#define SKYB0	Vector(SKY2, SKY_HEIGHT1, SKY0)
#define SKYB1	Vector(SKY3, SKY_HEIGHT1, SKY1)
#define SKYB2	Vector(SKY3, SKY_HEIGHT1, SKY2)
#define SKYB3	Vector(SKY2, SKY_HEIGHT1, SKY3)
#define SKYB4	Vector(SKY1, SKY_HEIGHT1, SKY3)
#define SKYB5	Vector(SKY0, SKY_HEIGHT1, SKY2)
#define SKYB6	Vector(SKY0, SKY_HEIGHT1, SKY1)
#define SKYB7	Vector(SKY1, SKY_HEIGHT1, SKY0)
#define SKYC0	Vector(SKY2, SKY_HEIGHT2, SKY1)
#define SKYC1	Vector(SKY2, SKY_HEIGHT2, SKY2)
#define SKYC2	Vector(SKY1, SKY_HEIGHT2, SKY2)
#define SKYC3	Vector(SKY1, SKY_HEIGHT2, SKY1)

#define TEX0	0.008
#define TEX1	0.055
#define TEX2	0.500
#define TEX3	0.992

#define TEXX(x) ((float)(x) / 1024.0)

static _SkyPolyDef skyPolys[] = {
	_SkyPolyDef(Vertex(SKYA0, UV(TEXX(   0), TEX3)),
				Vertex(SKYB0, UV(TEXX(   0), TEX2)),
				Vertex(SKYB1, UV(TEXX( 128), TEX2)),
				Vertex(SKYA1, UV(TEXX( 128), TEX3))),
  
	_SkyPolyDef(Vertex(SKYA1, UV(TEXX( 128), TEX3)),
				Vertex(SKYB1, UV(TEXX( 128), TEX2)),
				Vertex(SKYB2, UV(TEXX( 256), TEX2)),
				Vertex(SKYA2, UV(TEXX( 256), TEX3))),
  
	_SkyPolyDef(Vertex(SKYA2, UV(TEXX( 256), TEX3)),
				Vertex(SKYB2, UV(TEXX( 256), TEX2)),
				Vertex(SKYB3, UV(TEXX( 384), TEX2)),
				Vertex(SKYA3, UV(TEXX( 384), TEX3))),
  
	_SkyPolyDef(Vertex(SKYA3, UV(TEXX( 384), TEX3)),
				Vertex(SKYB3, UV(TEXX( 384), TEX2)),
				Vertex(SKYB4, UV(TEXX( 512), TEX2)),
				Vertex(SKYA4, UV(TEXX( 512), TEX3))),
  
	_SkyPolyDef(Vertex(SKYA4, UV(TEXX( 512), TEX3)),
				Vertex(SKYB4, UV(TEXX( 512), TEX2)),
				Vertex(SKYB5, UV(TEXX( 640), TEX2)),
				Vertex(SKYA5, UV(TEXX( 640), TEX3))),
	
	_SkyPolyDef(Vertex(SKYA5, UV(TEXX( 640), TEX3)),
				Vertex(SKYB5, UV(TEXX( 640), TEX2)),
				Vertex(SKYB6, UV(TEXX( 768), TEX2)),
				Vertex(SKYA6, UV(TEXX( 768), TEX3))),
	
	_SkyPolyDef(Vertex(SKYA6, UV(TEXX( 768), TEX3)),
				Vertex(SKYB6, UV(TEXX( 768), TEX2)),
				Vertex(SKYB7, UV(TEXX( 896), TEX2)),
				Vertex(SKYA7, UV(TEXX( 896), TEX3))),
	
	_SkyPolyDef(Vertex(SKYA7, UV(TEXX( 896), TEX3)),
				Vertex(SKYB7, UV(TEXX( 896), TEX2)),
				Vertex(SKYB0, UV(TEXX(1024), TEX2)),
				Vertex(SKYA0, UV(TEXX(1024), TEX3))),

	_SkyPolyDef(Vertex(SKYB0, UV(TEXX(   0), TEX2)),
				Vertex(SKYC0, UV(TEXX(  64), TEX1)),
				Vertex(SKYB1, UV(TEXX( 128), TEX2))),

	_SkyPolyDef(Vertex(SKYB1, UV(TEXX( 128), TEX2)),
				Vertex(SKYC0, UV(TEXX( 128), TEX0)),
				Vertex(SKYC1, UV(TEXX( 256), TEX0)),
				Vertex(SKYB2, UV(TEXX( 256), TEX2))),

	_SkyPolyDef(Vertex(SKYB2, UV(TEXX( 256), TEX2)),
				Vertex(SKYC1, UV(TEXX( 320), TEX1)),
				Vertex(SKYB3, UV(TEXX( 384), TEX2))),

	_SkyPolyDef(Vertex(SKYB3, UV(TEXX( 384), TEX2)),
				Vertex(SKYC1, UV(TEXX( 384), TEX0)),
				Vertex(SKYC2, UV(TEXX( 512), TEX0)),
				Vertex(SKYB4, UV(TEXX( 512), TEX2))),
	
	_SkyPolyDef(Vertex(SKYB4, UV(TEXX( 512), TEX2)),
				Vertex(SKYC2, UV(TEXX( 576), TEX1)),
				Vertex(SKYB5, UV(TEXX( 640), TEX2))),
	
	_SkyPolyDef(Vertex(SKYB5, UV(TEXX( 640), TEX2)),
				Vertex(SKYC2, UV(TEXX( 640), TEX0)),
				Vertex(SKYC3, UV(TEXX( 768), TEX0)),
				Vertex(SKYB6, UV(TEXX( 768), TEX2))),
	
	_SkyPolyDef(Vertex(SKYB6, UV(TEXX( 768), TEX2)),
				Vertex(SKYC3, UV(TEXX( 832), TEX1)),
				Vertex(SKYB7, UV(TEXX( 896), TEX2))),
	
	_SkyPolyDef(Vertex(SKYB7, UV(TEXX( 896), TEX2)),
				Vertex(SKYC3, UV(TEXX( 896), TEX0)),
				Vertex(SKYC0, UV(TEXX(1024), TEX0)),
				Vertex(SKYB0, UV(TEXX(1024), TEX2))),
};

static _SkyPolyDef skyCap = 
	_SkyPolyDef(Vertex(SKYC0),
				Vertex(SKYC3),
				Vertex(SKYC2),
				Vertex(SKYC1));

void Sky::Draw(Clipper& rClipper) throw(Exception)
{
	rClipper.Context()->SetZMode(C3D_EZMODE_OFF, C3D_EZCMP_NEVER);

	rClipper.Context()->SetTexture(s_pSkyTexture);
	float savedFarClipPlane = rClipper.Stack()->FarClipPlane();
	rClipper.Stack()->SetFarClipPlane(100000);

	for(int i=0; i<SKYPOLYS_COUNT; i++)
	{
		if(rClipper.Stack()->IsFacing(skyPolys[i].normal))
			if(skyPolys[i].count == 3)
				rClipper.DrawTriangle(skyPolys[i].a, skyPolys[i].b, skyPolys[i].c, VERTEXTYPE_T);
			else
				rClipper.DrawQuad(skyPolys[i].a, skyPolys[i].b, skyPolys[i].c, skyPolys[i].d, VERTEXTYPE_T);
	}

	rClipper.Stack()->SetFarClipPlane(savedFarClipPlane);
}

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