1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 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 
28 unsigned char	*r_turb_pbase, *r_turb_pdest;
29 fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
30 int				*r_turb_turb;
31 int				r_turb_spancount;
32 
33 void D_DrawTurbulent8Span (void);
34 
35 
36 /*
37 =============
38 D_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 */
D_WarpScreen(void)44 void 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[MAXHEIGHT+(AMP2*2)];
53 	int		column[MAXWIDTH+(AMP2*2)];
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 
82 		for (u=0 ; u<scr_vrect.width ; u+=4)
83 		{
84 			dest[u+0] = row[turb[u+0]][col[u+0]];
85 			dest[u+1] = row[turb[u+1]][col[u+1]];
86 			dest[u+2] = row[turb[u+2]][col[u+2]];
87 			dest[u+3] = row[turb[u+3]][col[u+3]];
88 		}
89 	}
90 }
91 
92 
93 #if	!id386
94 
95 /*
96 =============
97 D_DrawTurbulent8Span
98 =============
99 */
D_DrawTurbulent8Span(void)100 void D_DrawTurbulent8Span (void)
101 {
102 	int		sturb, tturb;
103 
104 	do
105 	{
106 		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
107 		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
108 		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
109 		r_turb_s += r_turb_sstep;
110 		r_turb_t += r_turb_tstep;
111 	} while (--r_turb_spancount > 0);
112 }
113 
114 #endif	// !id386
115 
116 
117 /*
118 =============
119 Turbulent8
120 =============
121 */
Turbulent8(espan_t * pspan)122 void Turbulent8 (espan_t *pspan)
123 {
124 	int				count;
125 	fixed16_t		snext, tnext;
126 	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
127 	float			sdivz16stepu, tdivz16stepu, zi16stepu;
128 
129 	r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
130 
131 	r_turb_sstep = 0;	// keep compiler happy
132 	r_turb_tstep = 0;	// ditto
133 
134 	r_turb_pbase = (unsigned char *)cacheblock;
135 
136 	sdivz16stepu = d_sdivzstepu * 16;
137 	tdivz16stepu = d_tdivzstepu * 16;
138 	zi16stepu = d_zistepu * 16;
139 
140 	do
141 	{
142 		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
143 				(screenwidth * pspan->v) + pspan->u);
144 
145 		count = pspan->count;
146 
147 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
148 		du = (float)pspan->u;
149 		dv = (float)pspan->v;
150 
151 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
152 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
153 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
154 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
155 
156 		r_turb_s = (int)(sdivz * z) + sadjust;
157 		if (r_turb_s > bbextents)
158 			r_turb_s = bbextents;
159 		else if (r_turb_s < 0)
160 			r_turb_s = 0;
161 
162 		r_turb_t = (int)(tdivz * z) + tadjust;
163 		if (r_turb_t > bbextentt)
164 			r_turb_t = bbextentt;
165 		else if (r_turb_t < 0)
166 			r_turb_t = 0;
167 
168 		do
169 		{
170 		// calculate s and t at the far end of the span
171 			if (count >= 16)
172 				r_turb_spancount = 16;
173 			else
174 				r_turb_spancount = count;
175 
176 			count -= r_turb_spancount;
177 
178 			if (count)
179 			{
180 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
181 			// calculate s and t steps across span by shifting
182 				sdivz += sdivz16stepu;
183 				tdivz += tdivz16stepu;
184 				zi += zi16stepu;
185 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
186 
187 				snext = (int)(sdivz * z) + sadjust;
188 				if (snext > bbextents)
189 					snext = bbextents;
190 				else if (snext < 16)
191 					snext = 16;	// prevent round-off error on <0 steps from
192 								//  from causing overstepping & running off the
193 								//  edge of the texture
194 
195 				tnext = (int)(tdivz * z) + tadjust;
196 				if (tnext > bbextentt)
197 					tnext = bbextentt;
198 				else if (tnext < 16)
199 					tnext = 16;	// guard against round-off error on <0 steps
200 
201 				r_turb_sstep = (snext - r_turb_s) >> 4;
202 				r_turb_tstep = (tnext - r_turb_t) >> 4;
203 			}
204 			else
205 			{
206 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
207 			// can't step off polygon), clamp, calculate s and t steps across
208 			// span by division, biasing steps low so we don't run off the
209 			// texture
210 				spancountminus1 = (float)(r_turb_spancount - 1);
211 				sdivz += d_sdivzstepu * spancountminus1;
212 				tdivz += d_tdivzstepu * spancountminus1;
213 				zi += d_zistepu * spancountminus1;
214 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
215 				snext = (int)(sdivz * z) + sadjust;
216 				if (snext > bbextents)
217 					snext = bbextents;
218 				else if (snext < 16)
219 					snext = 16;	// prevent round-off error on <0 steps from
220 								//  from causing overstepping & running off the
221 								//  edge of the texture
222 
223 				tnext = (int)(tdivz * z) + tadjust;
224 				if (tnext > bbextentt)
225 					tnext = bbextentt;
226 				else if (tnext < 16)
227 					tnext = 16;	// guard against round-off error on <0 steps
228 
229 				if (r_turb_spancount > 1)
230 				{
231 					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
232 					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
233 				}
234 			}
235 
236 			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
237 			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
238 
239 			D_DrawTurbulent8Span ();
240 
241 			r_turb_s = snext;
242 			r_turb_t = tnext;
243 
244 		} while (count > 0);
245 
246 	} while ((pspan = pspan->pnext) != NULL);
247 }
248 
249 
250 #if	!id386
251 
252 /*
253 =============
254 D_DrawSpans8
255 =============
256 */
D_DrawSpans8(espan_t * pspan)257 void D_DrawSpans8 (espan_t *pspan)
258 {
259 	int				count, spancount;
260 	unsigned char	*pbase, *pdest;
261 	fixed16_t		s, t, snext, tnext, sstep, tstep;
262 	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
263 	float			sdivz8stepu, tdivz8stepu, zi8stepu;
264 
265 	sstep = 0;	// keep compiler happy
266 	tstep = 0;	// ditto
267 
268 	pbase = (unsigned char *)cacheblock;
269 
270 	sdivz8stepu = d_sdivzstepu * 8;
271 	tdivz8stepu = d_tdivzstepu * 8;
272 	zi8stepu = d_zistepu * 8;
273 
274 	do
275 	{
276 		pdest = (unsigned char *)((byte *)d_viewbuffer +
277 				(screenwidth * pspan->v) + pspan->u);
278 
279 		count = pspan->count;
280 
281 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
282 		du = (float)pspan->u;
283 		dv = (float)pspan->v;
284 
285 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
286 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
287 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
288 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
289 
290 		s = (int)(sdivz * z) + sadjust;
291 		if (s > bbextents)
292 			s = bbextents;
293 		else if (s < 0)
294 			s = 0;
295 
296 		t = (int)(tdivz * z) + tadjust;
297 		if (t > bbextentt)
298 			t = bbextentt;
299 		else if (t < 0)
300 			t = 0;
301 
302 		do
303 		{
304 		// calculate s and t at the far end of the span
305 			if (count >= 8)
306 				spancount = 8;
307 			else
308 				spancount = count;
309 
310 			count -= spancount;
311 
312 			if (count)
313 			{
314 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
315 			// calculate s and t steps across span by shifting
316 				sdivz += sdivz8stepu;
317 				tdivz += tdivz8stepu;
318 				zi += zi8stepu;
319 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
320 
321 				snext = (int)(sdivz * z) + sadjust;
322 				if (snext > bbextents)
323 					snext = bbextents;
324 				else if (snext < 8)
325 					snext = 8;	// prevent round-off error on <0 steps from
326 								//  from causing overstepping & running off the
327 								//  edge of the texture
328 
329 				tnext = (int)(tdivz * z) + tadjust;
330 				if (tnext > bbextentt)
331 					tnext = bbextentt;
332 				else if (tnext < 8)
333 					tnext = 8;	// guard against round-off error on <0 steps
334 
335 				sstep = (snext - s) >> 3;
336 				tstep = (tnext - t) >> 3;
337 			}
338 			else
339 			{
340 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
341 			// can't step off polygon), clamp, calculate s and t steps across
342 			// span by division, biasing steps low so we don't run off the
343 			// texture
344 				spancountminus1 = (float)(spancount - 1);
345 				sdivz += d_sdivzstepu * spancountminus1;
346 				tdivz += d_tdivzstepu * spancountminus1;
347 				zi += d_zistepu * spancountminus1;
348 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
349 				snext = (int)(sdivz * z) + sadjust;
350 				if (snext > bbextents)
351 					snext = bbextents;
352 				else if (snext < 8)
353 					snext = 8;	// prevent round-off error on <0 steps from
354 								//  from causing overstepping & running off the
355 								//  edge of the texture
356 
357 				tnext = (int)(tdivz * z) + tadjust;
358 				if (tnext > bbextentt)
359 					tnext = bbextentt;
360 				else if (tnext < 8)
361 					tnext = 8;	// guard against round-off error on <0 steps
362 
363 				if (spancount > 1)
364 				{
365 					sstep = (snext - s) / (spancount - 1);
366 					tstep = (tnext - t) / (spancount - 1);
367 				}
368 			}
369 
370 			do
371 			{
372 				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
373 				s += sstep;
374 				t += tstep;
375 			} while (--spancount > 0);
376 
377 			s = snext;
378 			t = tnext;
379 
380 		} while (count > 0);
381 
382 	} while ((pspan = pspan->pnext) != NULL);
383 }
384 
385 #endif
386 
387 
388 #if	!id386
389 
390 /*
391 =============
392 D_DrawZSpans
393 =============
394 */
D_DrawZSpans(espan_t * pspan)395 void D_DrawZSpans (espan_t *pspan)
396 {
397 	int				count, doublecount, izistep;
398 	int				izi;
399 	short			*pdest;
400 	unsigned		ltemp;
401 	double			zi;
402 	float			du, dv;
403 
404 // FIXME: check for clamping/range problems
405 // we count on FP exceptions being turned off to avoid range problems
406 	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
407 
408 	do
409 	{
410 		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
411 
412 		count = pspan->count;
413 
414 	// calculate the initial 1/z
415 		du = (float)pspan->u;
416 		dv = (float)pspan->v;
417 
418 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
419 	// we count on FP exceptions being turned off to avoid range problems
420 		izi = (int)(zi * 0x8000 * 0x10000);
421 
422 		if ((long)pdest & 0x02)
423 		{
424 			*pdest++ = (short)(izi >> 16);
425 			izi += izistep;
426 			count--;
427 		}
428 
429 		if ((doublecount = count >> 1) > 0)
430 		{
431 			do
432 			{
433 				ltemp = izi >> 16;
434 				izi += izistep;
435 				ltemp |= izi & 0xFFFF0000;
436 				izi += izistep;
437 				*(int *)pdest = ltemp;
438 				pdest += 2;
439 			} while (--doublecount > 0);
440 		}
441 
442 		if (count & 1)
443 			*pdest = (short)(izi >> 16);
444 
445 	} while ((pspan = pspan->pnext) != NULL);
446 }
447 
448 #endif
449 
450