/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// d_edge.c

#include "quakedef.h"
#include "d_local.h"

#include "ds.h"

//float	turbsin[] =
//{
//	#include "gl_warp_sin.h"
//};
//#define TURBSCALE (256.0 / (2 * M_PI))

#define USE_3D
//#define DS_MIPLEVEL 1

static int	miplevel;

float		scale_for_mip;
int			screenwidth;
int			ubasestep, errorterm, erroradjustup, erroradjustdown;
int			vstartscan;

// FIXME: should go away
extern void			R_RotateBmodel (void);
extern void			R_TransformFrustum (void);

vec3_t		transformed_modelorg;

extern cvar_t ds_draw_imposters;
extern cvar_t ds_turb_transparency;
extern int turb_transparency;

int mip_used = 0;

/*
==============
D_DrawPoly

==============
*/

#define RGB15(r,g,b)  ((r)|((g)<<5)|((b)<<10))
#define RGB5(r,g,b)  ((r)|((g)<<5)|((b)<<10))
#define RGB8(r,g,b)  (((r)>>3)|(((g)>>3)<<5)|(((b)>>3)<<10))

#define floattov16(n)         ((short int)((n) * (1 << 12)))

#define GFX_FIFO				(*(volatile unsigned int *) 0x04000400)
#define GFX_COLOR				(*(volatile unsigned int *) 0x4000480)
#define GFX_TEX_COORD			(*(volatile unsigned int *) 0x04000488)
#define GFX_VERTEX16			(*(volatile unsigned int *) 0x0400048C)
#define GFX_BEGIN				(*(volatile unsigned int *) 0x04000500)
#define TEXTURE_PACK(u,v)		(((u) << 16) | (v & 0xFFFF))

#define DS_COLOUR3B(red, green, blue) GFX_COLOR = (volatile unsigned int)RGB15(red>>3, green>>3, blue>>3)
#define DS_COLOUR3B_FIFO(red, green, blue)	GFX_FIFO = RGB15(red>>3, green>>3, blue>>3)
#define DS_COLOUR3B_PACK(red, green, blue)	RGB15(red>>3, green>>3, blue>>3)

#define DS_TEXCOORD2T16(x, y) GFX_TEX_COORD = TEXTURE_PACK(x, y)
#define DS_TEXCOORD2T16_FIFO(x, y) GFX_FIFO = TEXTURE_PACK(x, y)
#define DS_TEXCOORD2T16_PACK(x, y) TEXTURE_PACK(x, y)

#define DS_VERTEX3V16(x, y, z) GFX_VERTEX16 = (y << 16) | (x & 0xFFFF); GFX_VERTEX16 = ((unsigned int)(unsigned short)z)
#define DS_VERTEX3V16_FIFO(x, y, z) GFX_FIFO = (y << 16) | (x & 0xFFFF); GFX_FIFO = ((unsigned int)(unsigned short)z)
#define DS_VERTEX3V16_PACK1(x, y, z) (y << 16) | (x & 0xFFFF)
#define DS_VERTEX3V16_PACK2(x, y, z) ((unsigned int)(unsigned short)z)

#define DS_BEGIN_TRIANGLE() GFX_BEGIN = 0

#define FIFO_COMMAND_PACK(c1,c2,c3,c4) (((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1))
#define REG2ID(r)				(unsigned char)( ( ((unsigned int)(&(r)))-0x04000400 ) >> 2 )
#define FIFO_NOP				REG2ID(GFX_FIFO)
#define FIFO_COLOR				REG2ID(GFX_COLOR)
#define FIFO_VERTEX16			REG2ID(GFX_VERTEX16)
#define FIFO_TEX_COORD			REG2ID(GFX_TEX_COORD)
#define FIFO_BEGIN				REG2ID(GFX_BEGIN)


void ds_pushmatrix(void);
void ds_popmatrix(void);
void ds_translatef(float x, float y, float z);
void ds_vertex3f(float x, float y, float z);
void ds_vertex3v16(short int x, short int y, short int z);
void ds_color3f(float red, float green, float blue);
void ds_color3b(unsigned char red, unsigned char green, unsigned char blue);
void ds_texcoord2f(float u, float v);
void ds_texcoord2t16(short u, short v);
bool bind_texture(int id);
int ds_gettexwidth(void);
int ds_gettexheight(void);
void ds_polyfmt(int poly_id, int trans, int depth);

unsigned char colour = 0;

int drawpolycount = 0;

float minx = 10;
float maxx = 0;
float miny = 10;
float maxy = 0;
float minz = 10;
float maxz = 0;

//float tri_scale = 0.006f;
//float tri2_scale = 0.006f;
float tri_scale = 1.0f / 256;
float tri2_scale = 1.0f / 256;
float tri_z = -0.8;

#ifdef USE_3D
int draw_world = 1;
int draw_tris = 1;
#else
int draw_world = 0;
int draw_tris = 0;
#endif

int s_div = 1;
int t_div = 1;
float znear = 0;
extern int tex_up;
void D_DrawAliasTri(int u, int v, int iz, int s, int t,
	int u2, int v2, int iz2, int s2, int t2,
	int u3, int v3, int iz3, int s3, int t3)
{
//	u -= (int)xcenter;
//	u2 -= (int)xcenter;
//	u3 -= (int)xcenter;
	
//	v -= (int)ycenter;
//	v2 -= (int)ycenter;
//	v3 -= (int)ycenter;
	
	ds_polyfmt(0, 31, 0);
	
	if (!draw_tris)
		return;
	
//	ds_bindtexture(r_notexture_mip->texture_handle);
//	ds_bindtexture(0);
//	printf("tex %d\n", (unsigned int)r_affinetridesc.pskindesc->pcachespot);
//	ds_bindtexture((unsigned int)r_affinetridesc.pskindesc->pcachespot + tex_up);

	drawpolycount++;
	DS_BEGIN_TRIANGLE();
	
//	if ((s != 0) || (t != 0) || (s2 != 0) || (t2 != 0) || (s3 != 0) || (t3 != 0))
//		printf("%d %d, %d %d, %d %d\n", s >> 16, t >> 16, s2 >> 16, t2 >> 16, s3 >> 16, t3 >> 16);
	
//	ds_color3b(255, 255, 255);
	
//	ds_texcoord2t16(0, 0);

	DS_TEXCOORD2T16(t >> 12, s >> 12);
	DS_VERTEX3V16(u << 4, v << 4, iz << 4);
	
	DS_TEXCOORD2T16(t2 >> 12, s2 >> 12);
	DS_VERTEX3V16(u2 << 4, v2 << 4, iz2 << 4);
	
	DS_TEXCOORD2T16(t3 >> 12, s3 >> 12);
	DS_VERTEX3V16(u3 << 4, v3 << 4, iz3 << 4);
	
//	printf("z %d %d %d\n", iz, iz2, iz3);
}

void D_DrawTri(int u, int v, int iz, float s, float t,
	int u2, int v2, int iz2, float s2, float t2,
	int u3, int v3, int iz3, float s3, float t3, int texture_handle)
{
	u -= (int)xcenter;
	u2 -= (int)xcenter;
	u3 -= (int)xcenter;
	
	v -= (int)ycenter;
	v2 -= (int)ycenter;
	v3 -= (int)ycenter;
	
	if (!draw_tris)
		return;
	
	if (!bind_texture(texture_handle) && ds_draw_imposters.isZero())
		return;
	
	int tex_width = ds_gettexwidth();
	int tex_height = ds_gettexheight();

	drawpolycount++;
	
	ds_begin_triangle();
	
	ds_color3b(255, 255, 255);
	
//	iz = 10.0f / tri_scale;
	iz = 5;
	
	ds_texcoord2t16((short)((t * tex_height) * 16), (short)((s * tex_width) * 16));
	
//	ds_vertex3f((float)u * tri_scale, -(float)v * tri_scale, (float)iz);
	ds_vertex3f((float)u * tri_scale, -(float)v * tri_scale, tri_z);
	
	ds_texcoord2t16((short)((t2 * tex_height) * 16), (short)((s2 * tex_width) * 16));
	
//	ds_vertex3f((float)u2 * tri_scale, -(float)v2 * tri_scale, (float)iz);
	ds_vertex3f((float)u2 * tri_scale, -(float)v2 * tri_scale, tri_z);
	
	ds_texcoord2t16((short)((t3 * tex_height) * 16), (short)((s3 * tex_width) * 16));
	
//	ds_vertex3f((float)u3 * tri_scale, -(float)v3 * tri_scale, (float)iz);
	ds_vertex3f((float)u3 * tri_scale, -(float)v3 * tri_scale, tri_z);
	
	ds_end();
}

typedef short int t16;       // text coordinate 12.4 fixed point
#define floattot16(n)        ((t16)((n) * (1 << 4)))

unsigned short tex_shunt = 0;

texture_t *R_TextureAnimation (texture_t *base);

//int ds_brightness = 64;
#define DS_BRIGHTNESS 48
extern int lower_sky_handle, upper_sky_handle;

extern int sky_shift;
extern int turb_s, turb_t;
extern int turb_s2, turb_t2;
unsigned int min_tris = 0;

//unsigned int tri_display_list[12 * 128];			//twelve entries per triangle

void D_DrawPoly (void)
{
	if (!draw_world)
		return;

	int count;
	int tri;

	int smax = (r_polydesc.pcurrentface->extents[0]>>4)+1;
	int tmax = (r_polydesc.pcurrentface->extents[1]>>4)+1;

	int lightmap_val = 255;
	if ((int)r_polydesc.pcurrentface->samples != (1 << 10))
		lightmap_val = (int)r_polydesc.pcurrentface->samples;
	
	int comb_brightness = 0;
	int added = 0;
	
	for (int count = 0; count < MAXLIGHTMAPS && r_polydesc.pcurrentface->styles[count] != 255; count++, added++)
		comb_brightness += lightmap_val * d_lightstylevalue[r_polydesc.pcurrentface->styles[count]];
	
	if (added == 0)
		comb_brightness = 255;
	else
		comb_brightness = comb_brightness >> 8;
	
//	comb_brightness += ds_brightness;
	comb_brightness += DS_BRIGHTNESS;
	
	if (comb_brightness > 255)
		comb_brightness = 255;
	if (comb_brightness < 0)
		comb_brightness = 0;
	
//	unsigned int *display_list = (unsigned int *)((unsigned int)&tri_display_list/* | 0x400000*/);
//	*display_list++ = (r_polydesc.numverts - 3 + 1) * 16;
	
//	ds_color3b(comb_brightness, comb_brightness, comb_brightness);
	DS_COLOUR3B(comb_brightness, comb_brightness, comb_brightness);
	
	short int u_, v_, z_, s_, t_;
	u_ = r_polydesc.pverts[0].u_v16;
	v_ = r_polydesc.pverts[0].v_v16;
	z_ = r_polydesc.pverts[0].realz_v16;
	s_ = r_polydesc.pverts[0].s_;
	t_ = r_polydesc.pverts[0].t_;
	
//	if (min_tris < r_polydesc.numverts - 2)
//	{
//		min_tris = r_polydesc.numverts - 2;
//		printf("min tris %d\n", min_tris);
//	}

	ds_polyfmt(0, 31, 0);
	for (tri = 0; tri < r_polydesc.numverts - 3 + 1; tri++)
	{
		int start = tri;
		int end = tri + 3;
		{	
			short int u2_, v2_, z2_;
			short int u3_, v3_, z3_;
			short int s2_, t2_, s3_, t3_;
			
			u2_ = r_polydesc.pverts[start + 1].u_v16;
			v2_ = r_polydesc.pverts[start + 1].v_v16;
			z2_ = r_polydesc.pverts[start + 1].realz_v16;
			s2_ = r_polydesc.pverts[start + 1].s_;
			t2_ = r_polydesc.pverts[start + 1].t_;
			
			u3_ = r_polydesc.pverts[start + 2].u_v16;
			v3_ = r_polydesc.pverts[start + 2].v_v16;
			z3_ = r_polydesc.pverts[start + 2].realz_v16;
			s3_ = r_polydesc.pverts[start + 2].s_;
			t3_ = r_polydesc.pverts[start + 2].t_;
			
			drawpolycount++;
			DS_BEGIN_TRIANGLE();
			
			DS_TEXCOORD2T16(t_, s_);
			DS_VERTEX3V16(u_, v_, -z_);
			
			DS_TEXCOORD2T16(t2_, s2_);
			DS_VERTEX3V16(u2_, v2_, -z2_);
			
			DS_TEXCOORD2T16(t3_, s3_);
			DS_VERTEX3V16(u3_, v3_, -z3_);
			
//			GFX_FIFO = FIFO_COMMAND_PACK(FIFO_BEGIN, FIFO_TEX_COORD, FIFO_VERTEX16, FIFO_TEX_COORD);
//			
//			//0
//			GFX_FIFO = 0;
//			//1
//			DS_TEXCOORD2T16_FIFO(t_, s_);
//			//2
//			DS_VERTEX3V16_FIFO(u_, v_, -z_);
//			//3
//			DS_TEXCOORD2T16_FIFO(t2_, s2_);
//			
//			GFX_FIFO = FIFO_COMMAND_PACK(FIFO_VERTEX16, FIFO_TEX_COORD, FIFO_VERTEX16, FIFO_NOP);
//			
//			//0
//			DS_VERTEX3V16_FIFO(u2_, v2_, -z2_);
//			//1
//			DS_TEXCOORD2T16_FIFO(t3_, s3_);
//			//2
//			DS_VERTEX3V16_FIFO(u3_, v3_, -z3_);

//			display_list[tri * 16] = FIFO_COMMAND_PACK(FIFO_BEGIN, FIFO_TEX_COORD, FIFO_VERTEX16, FIFO_TEX_COORD);
//			
//			//0
//			display_list[tri * 16 + 1] = 0;
//			//1
//			display_list[tri * 16 + 2] = DS_TEXCOORD2T16_PACK(t_, s_);
//			//2
//			display_list[tri * 16 + 3] = DS_VERTEX3V16_PACK1(u_, v_, -z_);
//			display_list[tri * 16 + 4] = DS_VERTEX3V16_PACK2(u_, v_, -z_);
//			//3
//			display_list[tri * 16 + 5] = DS_TEXCOORD2T16_PACK(t2_, s2_);
//			
//			display_list[tri * 16 + 6] = FIFO_COMMAND_PACK(FIFO_VERTEX16, FIFO_TEX_COORD, FIFO_VERTEX16, FIFO_NOP);
//			
//			//0
//			display_list[tri * 16 + 7] = DS_VERTEX3V16_PACK1(u2_, v2_, -z2_);
//			display_list[tri * 16 + 8] = DS_VERTEX3V16_PACK2(u2_, v2_, -z2_);
//			//1
//			display_list[tri * 16 + 9] = DS_TEXCOORD2T16_PACK(t3_, s3_);
//			//2
//			display_list[tri * 16 + 10] = DS_VERTEX3V16_PACK1(u3_, v3_, -z3_);
//			display_list[tri * 16 + 11] = DS_VERTEX3V16_PACK2(u3_, v3_, -z3_);
//			
//			display_list[tri * 16 + 12] = 0; display_list[tri * 16 + 13] = 0; display_list[tri * 16 + 14] = 0; display_list[tri * 16 + 15] = 0;
		}
	}
	
	
//	display_list--;
//	
//	ds_fifo_dma_async(0, display_list);
}

void D_DrawSkyWaterPoly (void)
{
	bool draw_sky = false;
	bool draw_turb = false;
	
	if (!draw_world)
		return;

	int count;
	int tri;

	int smax = (r_polydesc.pcurrentface->extents[0]>>4)+1;
	int tmax = (r_polydesc.pcurrentface->extents[1]>>4)+1;

//	int lightmap_val = 255;
//	if (r_polydesc.pcurrentface->samples)
//		lightmap_val = (r_polydesc.pcurrentface->samples[0]
//			+ r_polydesc.pcurrentface->samples[smax - 1]
//			+ r_polydesc.pcurrentface->samples[(tmax - 1) * smax]
//			+ r_polydesc.pcurrentface->samples[smax * tmax - 1]) >> 2;

	int lightmap_val = 255;
	if ((int)r_polydesc.pcurrentface->samples != (1 << 10))
		lightmap_val = (int)r_polydesc.pcurrentface->samples;
	
	int comb_brightness = 0;
	int added = 0;
	
	for (int count = 0; count < MAXLIGHTMAPS && r_polydesc.pcurrentface->styles[count] != 255; count++, added++)
		comb_brightness += lightmap_val * d_lightstylevalue[r_polydesc.pcurrentface->styles[count]];
	
	if (added == 0)
		comb_brightness = 255;
	else
		comb_brightness = comb_brightness >> 8;
	
//	comb_brightness += ds_brightness;
	comb_brightness += DS_BRIGHTNESS;
	
	if (comb_brightness > 255)
		comb_brightness = 255;
	if (comb_brightness < 0)
		comb_brightness = 0;
	
//	ds_color3b(comb_brightness, comb_brightness, comb_brightness);
	DS_COLOUR3B(comb_brightness, comb_brightness, comb_brightness);
	
	short int u_, v_, z_, s_, t_;
	u_ = r_polydesc.pverts[0].u_v16;
	v_ = r_polydesc.pverts[0].v_v16;
	z_ = r_polydesc.pverts[0].realz_v16;
	s_ = r_polydesc.pverts[0].s_;
	t_ = r_polydesc.pverts[0].t_;
	
	if (r_polydesc.pcurrentface->flags & SURF_DRAWSKY)
	{
		draw_sky = true;
		s_ = (s_ >> 2) + sky_shift;
		t_ = (t_ >> 2) + sky_shift;
		
		int temp = s_;
		s_ = t_;
		t_ = -temp;
	}
	
	if (r_polydesc.pcurrentface->flags & SURF_DRAWTURB)
	{
		draw_turb = true;
		s_ += turb_s;
		t_ += turb_t;
	}
	
	for (tri = 0; tri < r_polydesc.numverts - 3 + 1; tri++)
	{
		int start = tri;
		int end = tri + 3;
		{	
			short int u2_, v2_, z2_;
			short int u3_, v3_, z3_;
			short int s2_, t2_, s3_, t3_;
			
			u2_ = r_polydesc.pverts[start + 1].u_v16;
			v2_ = r_polydesc.pverts[start + 1].v_v16;
			z2_ = r_polydesc.pverts[start + 1].realz_v16;
			s2_ = r_polydesc.pverts[start + 1].s_;
			t2_ = r_polydesc.pverts[start + 1].t_;
			
			u3_ = r_polydesc.pverts[start + 2].u_v16;
			v3_ = r_polydesc.pverts[start + 2].v_v16;
			z3_ = r_polydesc.pverts[start + 2].realz_v16;
			s3_ = r_polydesc.pverts[start + 2].s_;
			t3_ = r_polydesc.pverts[start + 2].t_;
			
			if (draw_sky)
			{
				s2_ = (s2_ >> 2) + sky_shift;
				t2_ = (t2_ >> 2) + sky_shift;
				s3_ = (s3_ >> 2) + sky_shift;
				t3_ = (t3_ >> 2) + sky_shift;
				
				int temp2 = s2_;
				s2_ = t2_;
				t2_ = -temp2;
				
				int temp3 = s3_;
				s3_ = t3_;
				t3_ = -temp3;
				
//				ds_bindtexture(upper_sky_handle);
				bind_texture(upper_sky_handle);
				ds_polyfmt(0, 31, 0);
			}
			if (draw_turb)
			{
				s2_ -= turb_s2;
				t2_ -= turb_t;
				
				s3_ += turb_s;
				t3_ -= turb_t2;
				
				if (turb_transparency < 31)
					ds_polyfmt(1, turb_transparency, 0);
			}

			drawpolycount++;
			DS_BEGIN_TRIANGLE();
			
			DS_TEXCOORD2T16(t_, s_);
			DS_VERTEX3V16(u_, v_, z_);
			
			DS_TEXCOORD2T16(t2_, s2_);
			DS_VERTEX3V16(u2_, v2_, z2_);
			
			DS_TEXCOORD2T16(t3_, s3_);
			DS_VERTEX3V16(u3_, v3_, z3_);
			
			if (draw_sky)
			{
//				ds_bindtexture(lower_sky_handle);
				bind_texture(lower_sky_handle);
				ds_polyfmt(1, 31, 1);
				
				drawpolycount++;
				DS_BEGIN_TRIANGLE();
				
				DS_TEXCOORD2T16((t_ - sky_shift), (s_ + sky_shift));
				DS_VERTEX3V16(u_, v_, z_);
				
				DS_TEXCOORD2T16((t2_ - sky_shift), (s2_ + sky_shift));
				DS_VERTEX3V16(u2_, v2_, z2_);
				
				DS_TEXCOORD2T16((t3_ - sky_shift), (s3_ + sky_shift));
				DS_VERTEX3V16(u3_, v3_, z3_);
			}
		}
	}
	ds_polyfmt(0, 31, 0);
}


/*
=============
D_MipLevelForScale
=============
*/
#ifndef USE_3D
int D_MipLevelForScale (float scale)
{
	int		lmiplevel;

	if (scale >= d_scalemip[0] )
		lmiplevel = 0;
	else if (scale >= d_scalemip[1] )
		lmiplevel = 1;
	else if (scale >= d_scalemip[2] )
		lmiplevel = 2;
	else
		lmiplevel = 3;

	if (lmiplevel < d_minmip)
		lmiplevel = d_minmip;

	return lmiplevel;
}


/*
==============
D_DrawSolidSurface
==============
*/

// FIXME: clean this up

void D_DrawSolidSurface (surf_t *surf, int color)
{
	espan_t	*span;
	byte	*pdest;
	int		u, u2, pix;
	
	pix = (color<<24) | (color<<16) | (color<<8) | color;
	for (span=surf->spans ; span ; span=span->pnext)
	{
		pdest = (byte *)d_viewbuffer + screenwidth*span->v;
		u = span->u;
		u2 = span->u + span->count - 1;
		((byte *)pdest)[u] = pix;

		if (u2 - u < 8)
		{
			for (u++ ; u <= u2 ; u++)
				((byte *)pdest)[u] = pix;
		}
		else
		{
			for (u++ ; u & 3 ; u++)
				((byte *)pdest)[u] = pix;

			u2 -= 4;
			for ( ; u <= u2 ; u+=4)
				*(int *)((byte *)pdest + u) = pix;
			u2 += 4;
			for ( ; u <= u2 ; u++)
				((byte *)pdest)[u] = pix;
		}
	}
}


/*
==============
D_CalcGradients
==============
*/
void D_CalcGradients (msurface_t *pface)
{
	mplane_t	*pplane;
	float		mipscale;
	vec3_t		p_temp1;
	vec3_t		p_saxis, p_taxis;
	float		t;

	pplane = pface->plane;

	mipscale = 1.0 / (float)(1 << miplevel);

	TransformVector (pface->texinfo->vecs[0], p_saxis);
	TransformVector (pface->texinfo->vecs[1], p_taxis);

	t = xscaleinv * mipscale;
	d_sdivzstepu = p_saxis[0] * t;
	d_tdivzstepu = p_taxis[0] * t;

	t = yscaleinv * mipscale;
	d_sdivzstepv = -p_saxis[1] * t;
	d_tdivzstepv = -p_taxis[1] * t;

	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
			ycenter * d_sdivzstepv;
	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
			ycenter * d_tdivzstepv;

	VectorScale (transformed_modelorg, mipscale, p_temp1);

	t = 0x10000*mipscale;
	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
			((pface->texturemins[0] << 16) >> miplevel)
			+ pface->texinfo->vecs[0][3]*t;
	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
			((pface->texturemins[1] << 16) >> miplevel)
			+ pface->texinfo->vecs[1][3]*t;

//
// -1 (-epsilon) so we never wander off the edge of the texture
//
	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
}


/*
==============
D_DrawSurfaces
==============
*/
void D_DrawSurfaces (void)
{
	surf_t			*s;
	msurface_t		*pface;
	surfcache_t		*pcurrentcache;
	vec3_t			world_transformed_modelorg;
	vec3_t			local_modelorg;

	currententity = &cl_entities[0];
	TransformVector (modelorg, transformed_modelorg);
	VectorCopy (transformed_modelorg, world_transformed_modelorg);

// TODO: could preset a lot of this at mode set time
	if (r_drawflat.value)
	{
		for (s = &surfaces[1] ; s<surface_p ; s++)
		{
			if (!s->spans)
				continue;

			d_zistepu = s->d_zistepu;
			d_zistepv = s->d_zistepv;
			d_ziorigin = s->d_ziorigin;

			D_DrawSolidSurface (s, (int)s->data & 0xFF);
			D_DrawZSpans (s->spans);
		}
	}
	else
	{
		for (s = &surfaces[1] ; s<surface_p ; s++)
		{
			if (!s->spans)
				continue;

			r_drawnpolycount++;

			d_zistepu = s->d_zistepu;
			d_zistepv = s->d_zistepv;
			d_ziorigin = s->d_ziorigin;

			if (s->flags & SURF_DRAWSKY)
			{
				if (!r_skymade)
				{
					R_MakeSky ();
				}

				D_DrawSkyScans8 (s->spans);
				D_DrawZSpans (s->spans);
			}
			else if (s->flags & SURF_DRAWBACKGROUND)
			{
			// set up a gradient for the background surface that places it
			// effectively at infinity distance from the viewpoint
				d_zistepu = 0;
				d_zistepv = 0;
				d_ziorigin = -0.9;

				D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF);
				D_DrawZSpans (s->spans);
			}
			else if (s->flags & SURF_DRAWTURB)
			{
				pface = (msurface_t *)s->data;
				miplevel = 0;
				cacheblock = (pixel_t *)
						((byte *)pface->texinfo->texture +
						pface->texinfo->texture->offsets[0]);
				cachewidth = 64;

				if (s->insubmodel)
				{
				// FIXME: we don't want to do all this for every polygon!
				// TODO: store once at start of frame
					currententity = s->entity;	//FIXME: make this passed in to
												// R_RotateBmodel ()
					VectorSubtract (r_origin, currententity->origin,
							local_modelorg);
					TransformVector (local_modelorg, transformed_modelorg);

					R_RotateBmodel ();	// FIXME: don't mess with the frustum,
										// make entity passed in
				}

				D_CalcGradients (pface);
				Turbulent8 (s->spans);
				D_DrawZSpans (s->spans);

				if (s->insubmodel)
				{
				//
				// restore the old drawing state
				// FIXME: we don't want to do this every time!
				// TODO: speed up
				//
					currententity = &cl_entities[0];
					VectorCopy (world_transformed_modelorg,
								transformed_modelorg);
					VectorCopy (base_vpn, vpn);
					VectorCopy (base_vup, vup);
					VectorCopy (base_vright, vright);
					VectorCopy (base_modelorg, modelorg);
					R_TransformFrustum ();
				}
			}
			else
			{
				if (s->insubmodel)
				{
				// FIXME: we don't want to do all this for every polygon!
				// TODO: store once at start of frame
					currententity = s->entity;	//FIXME: make this passed in to
												// R_RotateBmodel ()
					VectorSubtract (r_origin, currententity->origin, local_modelorg);
					TransformVector (local_modelorg, transformed_modelorg);

					R_RotateBmodel ();	// FIXME: don't mess with the frustum,
										// make entity passed in
				}

				pface = (msurface_t *)s->data;
//				miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip
//				* pface->texinfo->mipadjust);
//				miplevel = 2;
				miplevel = mip_used;

			// FIXME: make this passed in to D_CacheSurface
				pcurrentcache = D_CacheSurface (pface, miplevel);

				cacheblock = (pixel_t *)pcurrentcache->data;
				cachewidth = pcurrentcache->width;

				D_CalcGradients (pface);

				(*d_drawspans) (s->spans);

				D_DrawZSpans (s->spans);

				if (s->insubmodel)
				{
				//
				// restore the old drawing state
				// FIXME: we don't want to do this every time!
				// TODO: speed up
				//
					currententity = &cl_entities[0];
					VectorCopy (world_transformed_modelorg,
								transformed_modelorg);
					VectorCopy (base_vpn, vpn);
					VectorCopy (base_vup, vup);
					VectorCopy (base_vright, vright);
					VectorCopy (base_modelorg, modelorg);
					R_TransformFrustum ();
				}
			}
		}
	}
}
#endif
