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_scan.c
21//
22// Portable C scan-level rasterization code, all pixel depths.
23
24#include "quakedef.h"
25#include "r_local.h"
26#include "d_local.h"
27
28unsigned char	*r_turb_pbase, *r_turb_pdest;
29fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
30int				*r_turb_turb;
31int				r_turb_spancount;
32
33void D_DrawTurbulent8Span (void);
34
35
36/*
37=============
38D_WarpScreen
39
40// this performs a slight compression of the screen at the same time as
41// the sine warp, to keep the edges from wrapping
42=============
43*/
44void D_WarpScreen (void)
45{
46	int		w, h;
47	int		u,v;
48	byte	*dest;
49	int		*turb;
50	int		*col;
51	byte	**row;
52	byte	*rowptr[1024];
53	int		column[1280];
54	float	wratio, hratio;
55
56	w = r_refdef.vrect.width;
57	h = r_refdef.vrect.height;
58
59	wratio = w / (float)scr_vrect.width;
60	hratio = h / (float)scr_vrect.height;
61
62	for (v=0 ; v<scr_vrect.height+AMP2*2 ; v++)
63	{
64		rowptr[v] = d_viewbuffer + (r_refdef.vrect.y * screenwidth) +
65				 (screenwidth * (int)((float)v * hratio * h / (h + AMP2 * 2)));
66	}
67
68	for (u=0 ; u<scr_vrect.width+AMP2*2 ; u++)
69	{
70		column[u] = r_refdef.vrect.x +
71				(int)((float)u * wratio * w / (w + AMP2 * 2));
72	}
73
74	turb = intsintable + ((int)(cl.time*SPEED)&(CYCLE-1));
75	dest = vid.buffer + scr_vrect.y * vid.rowbytes + scr_vrect.x;
76
77	for (v=0 ; v<scr_vrect.height ; v++, dest += vid.rowbytes)
78	{
79		col = &column[turb[v]];
80		row = &rowptr[v];
81		for (u=0 ; u<scr_vrect.width ; u+=4)
82		{
83			dest[u+0] = row[turb[u+0]][col[u+0]];
84			dest[u+1] = row[turb[u+1]][col[u+1]];
85			dest[u+2] = row[turb[u+2]][col[u+2]];
86			dest[u+3] = row[turb[u+3]][col[u+3]];
87		}
88	}
89}
90
91
92#if	!id386
93
94/*
95=============
96D_DrawTurbulent8Span
97=============
98*/
99void D_DrawTurbulent8Span (void)
100{
101	int		sturb, tturb;
102
103	do
104	{
105		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
106		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
107		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
108		r_turb_s += r_turb_sstep;
109		r_turb_t += r_turb_tstep;
110	} while (--r_turb_spancount > 0);
111}
112
113#endif	// !id386
114
115/*
116=============
117Turbulent8
118=============
119*/
120void Turbulent8 (espan_t *pspan)
121{
122	int				count;
123	fixed16_t		snext, tnext;
124	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
125	float			sdivz16stepu, tdivz16stepu, zi16stepu;
126
127	r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
128
129	r_turb_sstep = 0;	// keep compiler happy
130	r_turb_tstep = 0;	// ditto
131
132	r_turb_pbase = (unsigned char *)cacheblock;
133
134	sdivz16stepu = d_sdivzstepu * 16;
135	tdivz16stepu = d_tdivzstepu * 16;
136	zi16stepu = d_zistepu * 16;
137
138	do
139	{
140		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
141				(screenwidth * pspan->v) + pspan->u);
142
143		count = pspan->count;
144
145	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
146		du = (float)pspan->u;
147		dv = (float)pspan->v;
148
149		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
150		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
151		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
152		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
153
154		r_turb_s = (int)(sdivz * z) + sadjust;
155		if (r_turb_s > bbextents)
156			r_turb_s = bbextents;
157		else if (r_turb_s < 0)
158			r_turb_s = 0;
159
160		r_turb_t = (int)(tdivz * z) + tadjust;
161		if (r_turb_t > bbextentt)
162			r_turb_t = bbextentt;
163		else if (r_turb_t < 0)
164			r_turb_t = 0;
165
166		do
167		{
168		// calculate s and t at the far end of the span
169			if (count >= 16)
170				r_turb_spancount = 16;
171			else
172				r_turb_spancount = count;
173
174			count -= r_turb_spancount;
175
176			if (count)
177			{
178			// calculate s/z, t/z, zi->fixed s and t at far end of span,
179			// calculate s and t steps across span by shifting
180				sdivz += sdivz16stepu;
181				tdivz += tdivz16stepu;
182				zi += zi16stepu;
183				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
184
185				snext = (int)(sdivz * z) + sadjust;
186				if (snext > bbextents)
187					snext = bbextents;
188				else if (snext < 16)
189					snext = 16;	// prevent round-off error on <0 steps from
190								//  from causing overstepping & running off the
191								//  edge of the texture
192
193				tnext = (int)(tdivz * z) + tadjust;
194				if (tnext > bbextentt)
195					tnext = bbextentt;
196				else if (tnext < 16)
197					tnext = 16;	// guard against round-off error on <0 steps
198
199				r_turb_sstep = (snext - r_turb_s) >> 4;
200				r_turb_tstep = (tnext - r_turb_t) >> 4;
201			}
202			else
203			{
204			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
205			// can't step off polygon), clamp, calculate s and t steps across
206			// span by division, biasing steps low so we don't run off the
207			// texture
208				spancountminus1 = (float)(r_turb_spancount - 1);
209				sdivz += d_sdivzstepu * spancountminus1;
210				tdivz += d_tdivzstepu * spancountminus1;
211				zi += d_zistepu * spancountminus1;
212				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
213				snext = (int)(sdivz * z) + sadjust;
214				if (snext > bbextents)
215					snext = bbextents;
216				else if (snext < 16)
217					snext = 16;	// prevent round-off error on <0 steps from
218								//  from causing overstepping & running off the
219								//  edge of the texture
220
221				tnext = (int)(tdivz * z) + tadjust;
222				if (tnext > bbextentt)
223					tnext = bbextentt;
224				else if (tnext < 16)
225					tnext = 16;	// guard against round-off error on <0 steps
226
227				if (r_turb_spancount > 1)
228				{
229					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
230					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
231				}
232			}
233
234			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
235			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
236
237			D_DrawTurbulent8Span ();
238
239			r_turb_s = snext;
240			r_turb_t = tnext;
241
242		} while (count > 0);
243
244	} while ((pspan = pspan->pnext) != NULL);
245}
246
247
248#if	!id386
249
250/*
251=============
252D_DrawSpans8
253=============
254*/
255void D_DrawSpans8 (espan_t *pspan)
256{
257	int				count, spancount;
258	unsigned char	*pbase, *pdest;
259	fixed16_t		s, t, snext, tnext, sstep, tstep;
260	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
261	float			sdivz8stepu, tdivz8stepu, zi8stepu;
262
263	sstep = 0;	// keep compiler happy
264	tstep = 0;	// ditto
265
266	pbase = (unsigned char *)cacheblock;
267
268	sdivz8stepu = d_sdivzstepu * 8;
269	tdivz8stepu = d_tdivzstepu * 8;
270	zi8stepu = d_zistepu * 8;
271
272	do
273	{
274		pdest = (unsigned char *)((byte *)d_viewbuffer +
275				(screenwidth * pspan->v) + pspan->u);
276
277		count = pspan->count;
278
279	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
280		du = (float)pspan->u;
281		dv = (float)pspan->v;
282
283		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
284		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
285		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
286		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
287
288		s = (int)(sdivz * z) + sadjust;
289		if (s > bbextents)
290			s = bbextents;
291		else if (s < 0)
292			s = 0;
293
294		t = (int)(tdivz * z) + tadjust;
295		if (t > bbextentt)
296			t = bbextentt;
297		else if (t < 0)
298			t = 0;
299
300		do
301		{
302		// calculate s and t at the far end of the span
303			if (count >= 8)
304				spancount = 8;
305			else
306				spancount = count;
307
308			count -= spancount;
309
310			if (count)
311			{
312			// calculate s/z, t/z, zi->fixed s and t at far end of span,
313			// calculate s and t steps across span by shifting
314				sdivz += sdivz8stepu;
315				tdivz += tdivz8stepu;
316				zi += zi8stepu;
317				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
318
319				snext = (int)(sdivz * z) + sadjust;
320				if (snext > bbextents)
321					snext = bbextents;
322				else if (snext < 8)
323					snext = 8;	// prevent round-off error on <0 steps from
324								//  from causing overstepping & running off the
325								//  edge of the texture
326
327				tnext = (int)(tdivz * z) + tadjust;
328				if (tnext > bbextentt)
329					tnext = bbextentt;
330				else if (tnext < 8)
331					tnext = 8;	// guard against round-off error on <0 steps
332
333				sstep = (snext - s) >> 3;
334				tstep = (tnext - t) >> 3;
335			}
336			else
337			{
338			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
339			// can't step off polygon), clamp, calculate s and t steps across
340			// span by division, biasing steps low so we don't run off the
341			// texture
342				spancountminus1 = (float)(spancount - 1);
343				sdivz += d_sdivzstepu * spancountminus1;
344				tdivz += d_tdivzstepu * spancountminus1;
345				zi += d_zistepu * spancountminus1;
346				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
347				snext = (int)(sdivz * z) + sadjust;
348				if (snext > bbextents)
349					snext = bbextents;
350				else if (snext < 8)
351					snext = 8;	// prevent round-off error on <0 steps from
352								//  from causing overstepping & running off the
353								//  edge of the texture
354
355				tnext = (int)(tdivz * z) + tadjust;
356				if (tnext > bbextentt)
357					tnext = bbextentt;
358				else if (tnext < 8)
359					tnext = 8;	// guard against round-off error on <0 steps
360
361				if (spancount > 1)
362				{
363					sstep = (snext - s) / (spancount - 1);
364					tstep = (tnext - t) / (spancount - 1);
365				}
366			}
367
368			do
369			{
370				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
371				s += sstep;
372				t += tstep;
373			} while (--spancount > 0);
374
375			s = snext;
376			t = tnext;
377
378		} while (count > 0);
379
380	} while ((pspan = pspan->pnext) != NULL);
381}
382
383#endif
384
385
386#if	!id386
387
388/*
389=============
390D_DrawZSpans
391=============
392*/
393void D_DrawZSpans (espan_t *pspan)
394{
395	int				count, doublecount, izistep;
396	int				izi;
397	short			*pdest;
398	unsigned		ltemp;
399	double			zi;
400	float			du, dv;
401
402// FIXME: check for clamping/range problems
403// we count on FP exceptions being turned off to avoid range problems
404	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
405
406	do
407	{
408		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
409
410		count = pspan->count;
411
412	// calculate the initial 1/z
413		du = (float)pspan->u;
414		dv = (float)pspan->v;
415
416		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
417	// we count on FP exceptions being turned off to avoid range problems
418		izi = (int)(zi * 0x8000 * 0x10000);
419
420		if ((long)pdest & 0x02)
421		{
422			*pdest++ = (short)(izi >> 16);
423			izi += izistep;
424			count--;
425		}
426
427		if ((doublecount = count >> 1) > 0)
428		{
429			do
430			{
431				ltemp = izi >> 16;
432				izi += izistep;
433				ltemp |= izi & 0xFFFF0000;
434				izi += izistep;
435				*(int *)pdest = ltemp;
436				pdest += 2;
437			} while (--doublecount > 0);
438		}
439
440		if (count & 1)
441			*pdest = (short)(izi >> 16);
442
443	} while ((pspan = pspan->pnext) != NULL);
444}
445
446#endif
447