#include "driver2.h"
#include "sky.h"
#include "system.h"
#include "mission.h"
#include "models.h"
#include "draw.h"
#include "camera.h"
#include "main.h"
#include "debris.h"
#include "players.h"

struct RGB16
{
	short r;
	short g;
	short b;
	short pad;
};

struct FLAREREC
{
	RGB16 transparency;
	char size;
	short gapmod;
};

int sky_y_offset[4] = { -17, -17, -17, -17 };

unsigned char HorizonLookup[4][4] = {
	{0, 0, 20, 20},
	{20, 20, 0, 0},
	{0, 0, 20, 20},
	{0, 0, 20, 20},
};

unsigned char HorizonTextures[40] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
	0, 1, 2, 3, 4, 5, 6, 7,
	20, 21, 22, 23, 24, 25, 26, 27,
	16, 17, 18, 19
};


SVECTOR sun_position[4] = {
	{-32000,-11000,-5000},
	{-32000,-11000,-5000},
	{-32000,-11000,-5000},
	{-32000,-11000,-5000}
};

SVECTOR moon_position[4] = {
	{-32000,-11500,-18000},
	{-32000,-11500,-18000,},
	{-32000,-11500,-18000,},
	{-32000,-11500,-18000,}
};

SVECTOR moon_shadow_position[4] =
{
	{ 33536, 54036, 47536, 0 },
	{ 33536, 54036, 47536, 0 },
	{ 33536, 54036, 47536, 0 },
	{ 33536, 10500, 47536, 0 }
};

FLAREREC flare_info[8] =
{
	{
		{0,0,90},16, 48
	},
	{
		{80,40,4},48,72
	},
	{
		{90,0,0},48,96
	},
	{
		{0,90,0},16,144
	},
	{
		{0,0,90},64,160
	},
	{
		{90,90,0},32,184
	},
	{
		{90,0,0},32,208
	},
	{
		{0,0,90},48,15
	}
};

int tunnelDir[3][2] =
{
	{2000, 3064},
	{2048, 0},
	{2048, 4095}
};

VECTOR tunnelPos[3][2] =
{
	{
		{ -398650, 0, -161000, 0 },
		{ -340300, 2000, -103000, 0 }
	},
	{
		{ 272800, 0, 41200, 0 },
		{ 271963, 2000, 168187, 0 }
	},

	{
		{ -115100, 0, -193200, 0 },
		{ -113300, -400, -132501, 0 }
	}
};

UV skytexuv[28] = { 0 };
short skyclut[28];
short skytpage[28];

// [D] [T]
void LoadSky(void)
{
	char name[16];

	int skyNum;
	RECT16 rect;
	
	int offset;

	int flipped;
	int single;

	int u,v,x,y,ry;
	int tp_x, clut_x, i;

	i = 0;
	y = 0;
	offset = 0;
	flipped = 1;

	do {
		if (flipped) 
		{
			switch(y)
			{
				default:
					ry = 0;
					flipped = 0;
					single = 1;
					break;
				case 1:
					ry = 0;
					flipped = 0;
					single = 0;
					break;
				case 2:
					ry = 1;
					flipped = 0;
					single = 0;
					break;
				case 3:
					ry = 1;
					flipped = 1;
					single = 0;
					break;
				case 4:
					ry = 0;
					flipped = 1;
					single = 0;
					break;
				case 5:
					ry = 2;
					flipped = 0;
					single = 0;
					break;
				case 6:
					ry = 2;
					flipped = 1;
					single = 0;
					break;
			}
		}
		else
		{
			ry = 0;
			flipped = 0;
			single = 1;
		}

		x = 0;
		y++;

		clut_x = 320;
		tp_x = 320;

		v = ry * 84;

		do {
			u = x * 128;
		
			if (single)
			{
				skytexuv[i].u0 = u;
				skytexuv[i].v0 = v;
				skytexuv[i].u1 = u;
				skytexuv[i].v1 = v;
				skytexuv[i].u2 = u;
				skytexuv[i].v2 = v;
				skytexuv[i].u3 = u;
				skytexuv[i].v3 = v;
			}
			else if (flipped) 
			{
				skytexuv[i].u0 = u;
				skytexuv[i].v0 = v + 83;
				skytexuv[i].u1 = u + 127;
				skytexuv[i].v1 = v + 83;
				skytexuv[i].u2 = u;
				skytexuv[i].v2 = v;
				skytexuv[i].u3 = u + 127;
				skytexuv[i].v3 = v;
			}
			else
			{
				skytexuv[i].u0 = u;
				skytexuv[i].v0 = v;
				skytexuv[i].u1 = u + 127;
				skytexuv[i].v1 = v;
				skytexuv[i].u2 = u;
				skytexuv[i].v2 = v + 83;
				skytexuv[i].u3 = u + 127;
				skytexuv[i].v3 = v + 83;
			}
	
			skytpage[i] = GetTPage(0,0,tp_x & 0xffffffc0,ry * 84 & 768);
			skyclut[i] = GetClut(clut_x,ry + 252);

			tp_x += 32;
			clut_x += 16;

			x++;
			i++;
		} while (x < 4);
	
		flipped = (y < 7);
		
	} while (y < 7);

	if (GameLevel == 1)
		skyNum = 1;
	else if (GameLevel == 2)
		skyNum = 2;
	else if (GameLevel == 3)
		skyNum = 3;
	else
		skyNum = 0;

	if (gWeather - 1U < 2)
	{
		if (gTimeOfDay == 3)
			offset = 0x10000;
		else
			offset = 0x20000;
	}
	else
	{
		if (gTimeOfDay == 0)
			offset = 0x30000;
		else if (gTimeOfDay == 1)
			offset = 0;
		else if (gTimeOfDay == 2)
			offset = 0x40000;
		else if (gTimeOfDay == 3)
			offset = 0x10000;
	}

	sprintf(name, "DATA\\SKY%d.RAW", skyNum);
	LoadfileSeg(name, (char*)_primTab1, offset, 0x10000);

	setRECT(&rect, 320, 0, 128, 256);

	LoadImage(&rect, (u_long*)_primTab1);

	DrawSync(0);
}

// [D] [T]
#ifdef USE_PGXP
void DisplaySun(DVECTORF* pos, CVECTOR* col, int flare_col)
#else
void DisplaySun(DVECTOR* pos, CVECTOR* col, int flare_col)
#endif
{
	short sn, cs;
	int sz;

	POLY_FT4* polys;
	POLY_FT3* null;

	int u0, u1, v0, v2;
	short width, height;

	u0 = sun_texture.coords.u0;
	u1 = sun_texture.coords.u1;
	v0 = sun_texture.coords.v0;
	v2 = sun_texture.coords.v2;

	null = (POLY_FT3*)current->primptr;
	setPolyFT3(null);

	null->x0 = -1;
	null->y0 = -1;
	null->x1 = -1;
	null->y1 = -1;
	null->x2 = -1;
	null->y2 = -1;
	null->tpage = 0;

	addPrim(current->ot + 0x1079, null);
	current->primptr += sizeof(POLY_FT3);

	polys = (POLY_FT4*)current->primptr;
	setPolyFT4(polys);
	setSemiTrans(polys, 1);

	polys->r0 = col->r;
	polys->g0 = col->g;
	polys->b0 = col->b;

	width = (((u1 - (u0 - 1)) / 2) * 3) / 4;
	height = (((v2 - (v0 - 1)) / 2) * 3) / 4;

	polys->x0 = pos->vx - width;
	polys->y0 = pos->vy - height;
	polys->x1 = pos->vx + width;
	polys->y1 = pos->vy - height;
	polys->x2 = pos->vx - width;
	polys->y2 = pos->vy + height;
	polys->x3 = pos->vx + width;
	polys->y3 = pos->vy + height;

	polys->u0 = sun_texture.coords.u0;
	polys->v0 = sun_texture.coords.v0;
	polys->u1 = sun_texture.coords.u1;
	polys->v1 = sun_texture.coords.v1;
	polys->u2 = sun_texture.coords.u2;
	polys->v2 = sun_texture.coords.v2;
	polys->u3 = sun_texture.coords.u3;
	polys->v3 = sun_texture.coords.v3;
	polys->clut = sun_texture.clutid;
	polys->tpage = sun_texture.tpageid | 0x20;

	addPrim(current->ot + 0x1079, polys);
	current->primptr += sizeof(POLY_FT4);

	cs = RCOS(camera_angle.vy);  //rcossin_tbl[(camera_angle.vy & 0x1ffe) + 1];
	sn = RSIN(camera_angle.vy);  //rcossin_tbl[camera_angle.vy & 0x1ffe];

	sz = -(((flare_texture.coords.u1 - (flare_texture.coords.u0 - 1)) / 2) * 3) / 4;

	polys = (POLY_FT4*)current->primptr;
	setPolyFT4(polys);
	setSemiTrans(polys, 1);

	polys->r0 = (flare_col / 2);
	polys->g0 = (flare_col / 2);
	polys->b0 = (flare_col / 2);

	width = (cs - sn) * sz >> 0xc;
	height = (sn + cs) * sz >> 0xc;

	polys->x0 = pos->vx + width;
	polys->y0 = pos->vy + height;
	polys->x1 = pos->vx - height;
	polys->y1 = pos->vy + width;
	polys->x2 = pos->vx + height;
	polys->y2 = pos->vy - width;
	polys->x3 = pos->vx - width;
	polys->y3 = pos->vy - height;
	polys->u0 = flare_texture.coords.u0;
	polys->v0 = flare_texture.coords.v0;
	polys->u1 = flare_texture.coords.u1;
	polys->v1 = flare_texture.coords.v1;
	polys->u2 = flare_texture.coords.u2;
	polys->v2 = flare_texture.coords.v2;
	polys->u3 = flare_texture.coords.u3;
	polys->v3 = flare_texture.coords.v3;
	polys->clut = flare_texture.clutid;
	polys->tpage = flare_texture.tpageid | 0x20;

	addPrim(current->ot + 0x1078, polys);
	current->primptr += sizeof(POLY_FT4);
}

// [D] [T]
#ifdef USE_PGXP
void DisplayMoon(DVECTORF* pos, CVECTOR* col, int flip)
#else
void DisplayMoon(DVECTOR* pos, CVECTOR* col, int flip)
#endif
{
	short width;
	short height;
	
	POLY_FT3* null;
	POLY_FT4* polys;
	
	null = (POLY_FT3*)current->primptr;
	setPolyFT3(null);

	null->x0 = -1;
	null->y0 = -1;
	null->x1 = -1;
	null->y1 = -1;
	null->x2 = -1;
	null->y2 = -1;
	null->tpage = 0;

	addPrim(current->ot + 0x1079, null);

	current->primptr += sizeof(POLY_FT3);

	polys = (POLY_FT4*)current->primptr;

	setPolyFT4(polys);
	setSemiTrans(polys, 1);

	polys->r0 = col->r;
	polys->g0 = col->g;
	polys->b0 = col->b;

	width = (moon_texture.coords.u1 - (moon_texture.coords.u0 - 1)) / 2;
	height = (moon_texture.coords.v2 - (moon_texture.coords.v0 - 1)) / 2;

	if (flip != 0)
		height = -height;

	polys->x0 = pos->vx - width;
	polys->y0 = pos->vy - height;
	polys->x1 = pos->vx + width;
	polys->y1 = pos->vy - height;
	polys->x2 = pos->vx - width;
	polys->y2 = pos->vy + height;
	polys->x3 = pos->vx + width;
	polys->y3 = pos->vy + height;

	polys->u0 = moon_texture.coords.u0;
	polys->v0 = moon_texture.coords.v0;
	polys->u1 = moon_texture.coords.u1;
	polys->v1 = moon_texture.coords.v1;
	polys->u2 = moon_texture.coords.u2;
	polys->v2 = moon_texture.coords.v2;
	polys->u3 = moon_texture.coords.u3;
	polys->v3 = moon_texture.coords.v3;

	polys->clut = moon_texture.clutid;
	polys->tpage = moon_texture.tpageid | 0x20;

	addPrim(current->ot + 0x1079, polys);
	current->primptr += sizeof(POLY_FT4);
}

extern VECTOR dummy;
RECT16 sun_source = {
		1008,
		456,
		16,
		10
};

// [D] [T]
void DrawLensFlare(void)
{
	static char last_attempt_failed; // offset 0x0
	static ushort buffer[16*10];

	RECT16 viewp = { -1,-1,321,257 };

	int flarez;
	int distance_to_sun;
	int bufferY;
	int bufferX;
	POLY_FT4 *poly;
	FLAREREC *pFlareInfo;
	int shade;
	ushort *pwBuffer;
	DR_MOVE* sample_sun;
	int ygap;
	int xgap;
	int flare_col;
	int flaresize;
	
	int haze_col;

#ifdef USE_PGXP
	DVECTORF sun_pers_conv_position;
#else
	DVECTOR sun_pers_conv_position;
#endif
	
	RECT16 source;
	CVECTOR col;

	source = sun_source;

	if (gWeather - 1U <= 1 || gTimeOfDay == 0 || gTimeOfDay == 2)
		return;
	
	if (gTimeOfDay == 3)
		col.r = 128;
	else
		col.r = 254;

	flare_col = 0;

	col.g = col.r;
	col.b = col.r;

	// get the sun brightness from framebuffer copy
	if (gTimeOfDay != 3 && last_attempt_failed == 0)
	{
		pwBuffer = buffer;
		StoreImage(&source, (u_long*)buffer);

		bufferY = 0;
		do
		{
			bufferY++;
			bufferX = 0;

			do
			{
				if (*pwBuffer == 0xFFFF || *pwBuffer == 0x7fff)
					flare_col++;

				bufferX++;
				pwBuffer++;
			}
			while (bufferX < 12);

			pwBuffer += 4;
		}
		while (bufferY < 10);
	}

	gte_SetRotMatrix(&inv_camera_matrix);
	gte_SetTransVector(&dummy);

	if (gTimeOfDay == 3)
	{
		gte_ldv0(&moon_position[GameLevel]);
	}
	else
	{
		gte_ldv0(&sun_position[GameLevel]);
	}

	gte_rtps();

	gte_stsxy(&sun_pers_conv_position);

	gte_stszotz(&flarez);
	
	xgap = sun_pers_conv_position.vx - 160;
	ygap = sun_pers_conv_position.vy - 128;

	//sun_pers_conv_position.vy = (short)((u_int)sun_pers_conv_position >> 0x10);
	
	distance_to_sun = SquareRoot0(xgap * xgap + ygap * ygap);

	if (gTimeOfDay == 3)
	{
		if (distance_to_sun < 500)
		{
			DisplayMoon(&sun_pers_conv_position, &col, 0);
			col.r = 64;
			col.b = 64;
			col.g = 64;
			
			gte_ldv0(&moon_shadow_position[GameLevel]);
			gte_rtps();
			gte_stsxy(&sun_pers_conv_position);

			DisplayMoon(&sun_pers_conv_position, &col, 1);
		}
	}
	else
	{
		if (flarez > 0 && distance_to_sun < 500)
		{
			DisplaySun(&sun_pers_conv_position, &col, flare_col);
			
			haze_col = (60 - (distance_to_sun / 2)) * flare_col;
			
			add_haze((haze_col / 6 + (haze_col >> 0x1f) >> 3) - (haze_col >> 0x1f), haze_col >> 6, 7);
			shade = flare_col / 3 - (distance_to_sun * 80) / 500;
	
			if (shade > -1 && flare_col != 0)
			{
				pFlareInfo = flare_info;
				
				do
				{
					int xpos, ypos, gapmod;
					
					gapmod = (128 - pFlareInfo->gapmod) * 2;
					flaresize = (pFlareInfo->size / 2);
					
					xpos = (xgap * gapmod) / 256;
					ypos = (ygap * gapmod) / 256;

					poly = (POLY_FT4*)current->primptr;
					setPolyFT4(poly);
					setSemiTrans(poly, 1);

					poly->x0 = poly->x2 = (xpos + 160) - flaresize;
					poly->y0 = poly->y1 = (ypos + 128) - flaresize;

					poly->x1 = poly->x3 = poly->x0 + pFlareInfo->size;
					poly->y2 = poly->y3 = poly->y0 + pFlareInfo->size;

					poly->r0 = (pFlareInfo->transparency.r * shade >> 6);
					poly->g0 = (pFlareInfo->transparency.g * shade >> 6);
					poly->b0 = (pFlareInfo->transparency.b * shade >> 6);
					
					poly->u0 = lensflare_texture.coords.u0;
					poly->v0 = lensflare_texture.coords.v0;
					poly->u1 = lensflare_texture.coords.u1;
					poly->v1 = lensflare_texture.coords.v1;
					poly->u2 = lensflare_texture.coords.u2;
					poly->v2 = lensflare_texture.coords.v2 - 4;
					poly->u3 = lensflare_texture.coords.u3;
					poly->v3 = lensflare_texture.coords.v3 - 4;
					
					poly->clut = lensflare_texture.clutid;
					poly->tpage = lensflare_texture.tpageid | 0x20;

					addPrim(current->ot + 10, poly);
					current->primptr += sizeof(POLY_FT4);

					pFlareInfo++;
				}
				while (pFlareInfo < flare_info + 8);
			}
		}

#ifdef USE_PGXP
		// remap
		PsyX_GetPSXWidescreenMappedViewport(&viewp);
		sun_pers_conv_position.vx = RemapVal(sun_pers_conv_position.vx, float(viewp.x), float(viewp.w), 0.0f, 320.0f);
#endif
		
		sun_pers_conv_position.vx = sun_pers_conv_position.vx - 8;
		sun_pers_conv_position.vy = sun_pers_conv_position.vy - 4;
		
		// store framebuffer image of sun separately in VRAM
		if (sun_pers_conv_position.vx > -1 &&
			sun_pers_conv_position.vy > -1 &&
			sun_pers_conv_position.vx + 16 < 321 &&
			sun_pers_conv_position.vy + 10 < 257)
		{
			last_attempt_failed = 0;

			source.x = sun_pers_conv_position.vx;
			source.y = sun_pers_conv_position.vy + last->disp.disp.y;

#if 1//def PSX
			sample_sun = (DR_MOVE*)current->primptr;
			SetDrawMove(sample_sun, &source, 1008, 456);

			addPrim(current->ot + 0x20, sample_sun);
			current->primptr += sizeof(DR_MOVE);
#else
			// to avoid delays and uploads to GPU we're simply going to directly request from screen VRAM area
			sun_source = source;
#endif
		}
		else
		{
			last_attempt_failed = 1;
		}
	}
}

int gTunnelNum = -1;
int skyFade;

RGB16 skycolor = { 128,128,128 };

// [D] [T]
void TunnelSkyFade(void)
{
	int dX, dZ, diffZ, diffX;
	int len, l2;
	VECTOR* v2;
	VECTOR* v1;
	int tun;

	if (gTunnelNum == -1)
		return;

	if (GameLevel != 3 && gTunnelNum < 3)
		tun = gTunnelNum;
	else
		tun = 2;

	v1 = NULL;
	v2 = NULL;

	// HMM?
	// DIFF_ANGLES(camera_angle.vy, tunnelDir[tun][0]) + 1247 < 2495;

	if (DIFF_ANGLES(camera_angle.vy, tunnelDir[tun][0]) + 1247 < 2495) // (((tunnelDir[tun][0] - camera_angle.vy) + 2048 & 4095) - 801 < 2495)
		v1 = &tunnelPos[tun][0];

	if (DIFF_ANGLES(camera_angle.vy, tunnelDir[tun][1]) + 1247 < 2495) // (((tunnelDir[tun][1] - camera_angle.vy) + 2048 & 4095) - 801 < 2495)
		v2 = &tunnelPos[tun][1];

	if(v1 && v2)
	{
		dX = (v1->vx - player[0].pos[0]) >> 5;		// [A] smooth sky fade
		dZ = (v1->vz - player[0].pos[2]) >> 5;

		diffX = (v2->vx - player[0].pos[0]) >> 5;
		diffZ = (v2->vz - player[0].pos[2]) >> 5;

		len = (dX * dX + dZ * dZ);
		l2 = (diffX * diffX + diffZ * diffZ);

		if (l2 <= len)
			len = l2;
	}
	else if(v2)
	{
		diffX = (v2->vx - player[0].pos[0]) >> 5;
		diffZ = (v2->vz - player[0].pos[2]) >> 5;

		len = (diffX * diffX + diffZ * diffZ);
	}
	else if(v1)
	{
		diffX = (v1->vx - player[0].pos[0]) >> 5;
		diffZ = (v1->vz - player[0].pos[2]) >> 5;

		len = (diffX * diffX + diffZ * diffZ);
	}
	else
	{
		skyFade = 0;
		return;
	}

	// [A] smooth sky fade
	len >>= 12;

	if (len <= 128)
		skyFade = -len + 128;
	else
		skyFade = 0;
}

// [D] [T]
void calc_sky_brightness(void)
{
	int dawn;
	dawn = DawnCount >> 5;

	if(gTimeOfDay == 0 || gTimeOfDay == 2)
	{
		if (gTimeOfDay == 0)
		{
			skycolor.r = dawn + 41;
			skycolor.b = dawn + 28;
		}
		else if (gTimeOfDay == 2)
		{
			skycolor.r = 143 - dawn;
			skycolor.b = 128 - dawn;
		}

		if (skycolor.r < 26)
			skycolor.r = 26;
		else if (skycolor.r > 128)
			skycolor.r = 128;

		if (skycolor.b < 26)
			skycolor.b = 26;
		else if (skycolor.b > 128)
			skycolor.b = 128;

		skycolor.g = skycolor.b;
	}
	else
	{
		skycolor.b = 128;
		skycolor.g = 128;
		skycolor.r = 128;
	}
	
	if (gTunnelNum == -1 || 
		GameLevel == 0 ||
		GameLevel == 1 && gTunnelNum == 2 ||
		GameLevel == 2 ||
		GameLevel == 3 && gTunnelNum != 1)
		return;

	TunnelSkyFade();

	if (skycolor.r > skyFade)
		skycolor.r = skyFade;

	if (skycolor.g > skyFade)
		skycolor.g = skyFade;

	if (skycolor.b > skyFade)
		skycolor.b = skyFade;
}

#ifdef USE_PGXP
DVECTORF scratchPad_skyVertices[35];	// 1f800044
#else
#define scratchPad_skyVertices ((DVECTOR*)getScratchAddr(0x11))	// 1f800044
#endif

// [D] [T]
void PlotSkyPoly(POLYFT4* polys, int skytexnum, unsigned char r, unsigned char g, unsigned char b)
{
	POLYFT4* src;
	POLY_FT4* poly;

	src = polys;
	poly = (POLY_FT4*)current->primptr;

#ifdef USE_PGXP
	DVECTORF* outpoints = scratchPad_skyVertices;
#else
	DVECTOR* outpoints = scratchPad_skyVertices;
#endif

#ifdef PSX
	if ((outpoints[src->v0].vy > -1 || outpoints[src->v1].vy > -1 || outpoints[src->v2].vy > -1 || outpoints[src->v3].vy > -1) &&
		(outpoints[src->v0].vx > -1 || outpoints[src->v1].vx > -1 || outpoints[src->v2].vx > -1 || outpoints[src->v3].vx > -1) &&
		(outpoints[src->v0].vx < 321 || outpoints[src->v1].vx < 321 || outpoints[src->v2].vx < 321 || outpoints[src->v3].vx < 321))
#endif
	{
		setPolyFT4(poly);

		poly->r0 = r;
		poly->g0 = g;
		poly->b0 = b;

		*(u_int*)&poly->x0 = *(u_int*)&outpoints[src->v0].vx;
		*(u_int*)&poly->x1 = *(u_int*)&outpoints[src->v1].vx;
		*(u_int*)&poly->x2 = *(u_int*)&outpoints[src->v3].vx;
		*(u_int*)&poly->x3 = *(u_int*)&outpoints[src->v2].vx;
	
		*(ushort*)&poly->u0 = *(ushort*)&skytexuv[skytexnum].u2;
		*(ushort*)&poly->u1 = *(ushort*)&skytexuv[skytexnum].u3;
		*(ushort*)&poly->u2 = *(ushort*)&skytexuv[skytexnum].u0;
		*(ushort*)&poly->u3 = *(ushort*)&skytexuv[skytexnum].u1;
		
		poly->clut = skyclut[skytexnum];
		poly->tpage = skytpage[skytexnum];

		addPrim(current->ot + OTSIZE - 1, poly);

#if defined(USE_PGXP) && defined(USE_EXTENDED_PRIM_POINTERS)
		poly->pgxp_index = outpoints[src->v0].pgxp_index;
#endif 

		current->primptr += sizeof(POLY_FT4);
	}
}

// [D] [T]
void PlotHorizonMDL(MODEL* model, int horizontaboffset)
{
	SVECTOR* verts;

#ifdef USE_PGXP
	DVECTORF* dv;
#else
	DVECTOR* dv;
#endif

	int count;
	unsigned char* polys;
	int red, green, blue;
	int z;

	z = -1;
	verts = (SVECTOR*)model->vertices;
	dv = scratchPad_skyVertices;
	count = model->num_vertices;

#ifdef USE_PGXP
	PGXP_SetZOffsetScale(0.0f, 256.0f);
#endif

	do
	{
		gte_ldv3(verts, verts+1, verts+2);
		gte_rtpt();
		gte_stsxy3(dv, dv+1, dv+2);

		if(count == 15)
			gte_stszotz(&z);

#ifdef USE_PGXP
		// store PGXP index
		// HACK: -1 is needed here for some reason
		dv[0].pgxp_index = dv[1].pgxp_index = dv[2].pgxp_index = PGXP_GetIndex() - 1;
#endif
		dv += 3;
		verts += 3;
		count -= 3;
	} while (count);

#ifdef USE_PGXP
	PGXP_SetZOffsetScale(0.0f, 1.0f);
#endif

	if (z > 0)
	{
		int polySize;
		u_char* horizonTex = &HorizonTextures[horizontaboffset];
		polys = (unsigned char*)model->poly_block;
		polySize = PolySizes[*polys];

		red = skycolor.r;
		green = skycolor.g;
		blue = skycolor.b;
		
		// draw sky
		count = model->num_polys;
		do
		{
			PlotSkyPoly((POLYFT4*)polys, *horizonTex++, red, green, blue);
			polys += polySize;
		} while (--count > 8);

		red /= 2;
		green /= 2;
		blue /= 2;

		// draw it's reflection
		do
		{
			PlotSkyPoly((POLYFT4*)polys, *horizonTex++, red, green, blue);
			polys += polySize;
		} while (--count);
	}
}

// [D] [T]
void DrawSkyDome(void)
{
	VECTOR skyOfs = dummy;
	skyOfs.vy = sky_y_offset[GameLevel];

	gte_SetRotMatrix(&inv_camera_matrix);
	gte_SetTransVector(&skyOfs);
	
	calc_sky_brightness();

#ifdef PSX
	// FIXME: use frustrum angle instead?
	if (((camera_angle.vy - 1450U) & 4095) > 2250)
		PlotHorizonMDL(modelpointers[0], HorizonLookup[GameLevel][0]);

	if (((camera_angle.vy - 651U) & 4095) < 1799)
		PlotHorizonMDL(modelpointers[2], HorizonLookup[GameLevel][1]);

	if (((camera_angle.vy - 1701U) & 4095) < 1749)
		PlotHorizonMDL(modelpointers[3], HorizonLookup[GameLevel][2]);

	if (((camera_angle.vy - 400U) & 4095) > 2300)
		PlotHorizonMDL(modelpointers[1], HorizonLookup[GameLevel][3]);
#else
	// draw full sky - no need in frustrum culling
	PlotHorizonMDL(modelpointers[0], HorizonLookup[GameLevel][0]);
	PlotHorizonMDL(modelpointers[2], HorizonLookup[GameLevel][1]);
	PlotHorizonMDL(modelpointers[3], HorizonLookup[GameLevel][2]);
	PlotHorizonMDL(modelpointers[1], HorizonLookup[GameLevel][3]);
#endif

}

