1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// d_edge.c
21
22#include "quakedef.h"
23#include "d_local.h"
24
25static int	miplevel;
26
27float		scale_for_mip;
28int			screenwidth;
29int			ubasestep, errorterm, erroradjustup, erroradjustdown;
30int			vstartscan;
31
32// FIXME: should go away
33extern void			R_RotateBmodel (void);
34extern void			R_TransformFrustum (void);
35
36vec3_t		transformed_modelorg;
37
38/*
39==============
40D_DrawPoly
41
42==============
43*/
44void D_DrawPoly (void)
45{
46// this driver takes spans, not polygons
47}
48
49
50/*
51=============
52D_MipLevelForScale
53=============
54*/
55int D_MipLevelForScale (float scale)
56{
57	int		lmiplevel;
58
59	if (scale >= d_scalemip[0] )
60		lmiplevel = 0;
61	else if (scale >= d_scalemip[1] )
62		lmiplevel = 1;
63	else if (scale >= d_scalemip[2] )
64		lmiplevel = 2;
65	else
66		lmiplevel = 3;
67
68	if (lmiplevel < d_minmip)
69		lmiplevel = d_minmip;
70
71	return lmiplevel;
72}
73
74
75/*
76==============
77D_DrawSolidSurface
78==============
79*/
80
81// FIXME: clean this up
82
83void D_DrawSolidSurface (surf_t *surf, int color)
84{
85	espan_t	*span;
86	byte	*pdest;
87	int		u, u2, pix;
88
89	pix = (color<<24) | (color<<16) | (color<<8) | color;
90	for (span=surf->spans ; span ; span=span->pnext)
91	{
92		pdest = (byte *)d_viewbuffer + screenwidth*span->v;
93		u = span->u;
94		u2 = span->u + span->count - 1;
95		((byte *)pdest)[u] = pix;
96
97		if (u2 - u < 8)
98		{
99			for (u++ ; u <= u2 ; u++)
100				((byte *)pdest)[u] = pix;
101		}
102		else
103		{
104			for (u++ ; u & 3 ; u++)
105				((byte *)pdest)[u] = pix;
106
107			u2 -= 4;
108			for ( ; u <= u2 ; u+=4)
109				*(int *)((byte *)pdest + u) = pix;
110			u2 += 4;
111			for ( ; u <= u2 ; u++)
112				((byte *)pdest)[u] = pix;
113		}
114	}
115}
116
117
118/*
119==============
120D_CalcGradients
121==============
122*/
123void D_CalcGradients (msurface_t *pface)
124{
125	mplane_t	*pplane;
126	float		mipscale;
127	vec3_t		p_temp1;
128	vec3_t		p_saxis, p_taxis;
129	float		t;
130
131	pplane = pface->plane;
132
133	mipscale = 1.0 / (float)(1 << miplevel);
134
135	TransformVector (pface->texinfo->vecs[0], p_saxis);
136	TransformVector (pface->texinfo->vecs[1], p_taxis);
137
138	t = xscaleinv * mipscale;
139	d_sdivzstepu = p_saxis[0] * t;
140	d_tdivzstepu = p_taxis[0] * t;
141
142	t = yscaleinv * mipscale;
143	d_sdivzstepv = -p_saxis[1] * t;
144	d_tdivzstepv = -p_taxis[1] * t;
145
146	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
147			ycenter * d_sdivzstepv;
148	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
149			ycenter * d_tdivzstepv;
150
151	VectorScale (transformed_modelorg, mipscale, p_temp1);
152
153	t = 0x10000*mipscale;
154	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
155			((pface->texturemins[0] << 16) >> miplevel)
156			+ pface->texinfo->vecs[0][3]*t;
157	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
158			((pface->texturemins[1] << 16) >> miplevel)
159			+ pface->texinfo->vecs[1][3]*t;
160
161//
162// -1 (-epsilon) so we never wander off the edge of the texture
163//
164	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
165	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
166}
167
168
169/*
170==============
171D_DrawSurfaces
172==============
173*/
174void D_DrawSurfaces (void)
175{
176	surf_t			*s;
177	msurface_t		*pface;
178	surfcache_t		*pcurrentcache;
179	vec3_t			world_transformed_modelorg;
180	vec3_t			local_modelorg;
181
182	currententity = &r_worldentity;
183	TransformVector (modelorg, transformed_modelorg);
184	VectorCopy (transformed_modelorg, world_transformed_modelorg);
185
186// TODO: could preset a lot of this at mode set time
187	if (r_drawflat.value)
188	{
189		for (s = &surfaces[1] ; s<surface_p ; s++)
190		{
191			if (!s->spans)
192				continue;
193
194			d_zistepu = s->d_zistepu;
195			d_zistepv = s->d_zistepv;
196			d_ziorigin = s->d_ziorigin;
197
198#ifdef __alpha__
199			D_DrawSolidSurface (s, (int)((long)s->data & 0xFF));
200#else
201			D_DrawSolidSurface (s, (int)s->data & 0xFF);
202#endif
203			D_DrawZSpans (s->spans);
204		}
205	}
206	else
207	{
208		for (s = &surfaces[1] ; s<surface_p ; s++)
209		{
210			if (!s->spans)
211				continue;
212
213			r_drawnpolycount++;
214
215			d_zistepu = s->d_zistepu;
216			d_zistepv = s->d_zistepv;
217			d_ziorigin = s->d_ziorigin;
218
219			if (s->flags & SURF_DRAWSKY)
220			{
221				if (!r_skymade)
222				{
223					R_MakeSky ();
224				}
225
226				D_DrawSkyScans8 (s->spans);
227				D_DrawZSpans (s->spans);
228			}
229			else if (s->flags & SURF_DRAWBACKGROUND)
230			{
231			// set up a gradient for the background surface that places it
232			// effectively at infinity distance from the viewpoint
233				d_zistepu = 0;
234				d_zistepv = 0;
235				d_ziorigin = -0.9;
236
237				D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF);
238				D_DrawZSpans (s->spans);
239			}
240			else if (s->flags & SURF_DRAWTURB)
241			{
242				pface = s->data;
243				miplevel = 0;
244				cacheblock = (pixel_t *)
245						((byte *)pface->texinfo->texture +
246						pface->texinfo->texture->offsets[0]);
247				cachewidth = 64;
248
249				if (s->insubmodel)
250				{
251				// FIXME: we don't want to do all this for every polygon!
252				// TODO: store once at start of frame
253					currententity = s->entity;	//FIXME: make this passed in to
254												// R_RotateBmodel ()
255					VectorSubtract (r_origin, currententity->origin,
256							local_modelorg);
257					TransformVector (local_modelorg, transformed_modelorg);
258
259					R_RotateBmodel ();	// FIXME: don't mess with the frustum,
260										// make entity passed in
261				}
262
263				D_CalcGradients (pface);
264
265				Turbulent8 (s->spans);
266				D_DrawZSpans (s->spans);
267
268				if (s->insubmodel)
269				{
270				//
271				// restore the old drawing state
272				// FIXME: we don't want to do this every time!
273				// TODO: speed up
274				//
275					currententity = &r_worldentity;
276					VectorCopy (world_transformed_modelorg,
277								transformed_modelorg);
278					VectorCopy (base_vpn, vpn);
279					VectorCopy (base_vup, vup);
280					VectorCopy (base_vright, vright);
281					VectorCopy (base_modelorg, modelorg);
282					R_TransformFrustum ();
283				}
284			}
285			else
286			{
287				if (s->insubmodel)
288				{
289				// FIXME: we don't want to do all this for every polygon!
290				// TODO: store once at start of frame
291					currententity = s->entity;	//FIXME: make this passed in to
292												// R_RotateBmodel ()
293					VectorSubtract (r_origin, currententity->origin, local_modelorg);
294					TransformVector (local_modelorg, transformed_modelorg);
295
296					R_RotateBmodel ();	// FIXME: don't mess with the frustum,
297										// make entity passed in
298				}
299
300				pface = s->data;
301				miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip
302				* pface->texinfo->mipadjust);
303
304			// FIXME: make this passed in to D_CacheSurface
305				pcurrentcache = D_CacheSurface (pface, miplevel);
306
307				cacheblock = (pixel_t *)pcurrentcache->data;
308				cachewidth = pcurrentcache->width;
309
310				D_CalcGradients (pface);
311
312				(*d_drawspans) (s->spans);
313
314				D_DrawZSpans (s->spans);
315
316				if (s->insubmodel)
317				{
318				//
319				// restore the old drawing state
320				// FIXME: we don't want to do this every time!
321				// TODO: speed up
322				//
323					VectorCopy (world_transformed_modelorg,
324								transformed_modelorg);
325					VectorCopy (base_vpn, vpn);
326					VectorCopy (base_vup, vup);
327					VectorCopy (base_vright, vright);
328					VectorCopy (base_modelorg, modelorg);
329					R_TransformFrustum ();
330					currententity = &r_worldentity;
331				}
332			}
333		}
334	}
335}
336
337