1 /*
2 Copyright (C) 1997-2001 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 "r_local.h"
25 
26 unsigned char	*r_turb_pbase, *r_turb_pdest;
27 fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
28 int				*r_turb_turb;
29 int				r_turb_spancount;
30 
31 void D_DrawTurbulent8Span (void);
32 
33 
34 /*
35 =============
36 D_WarpScreen
37 
38 this performs a slight compression of the screen at the same time as
39 the sine warp, to keep the edges from wrapping
40 =============
41 */
D_WarpScreen(void)42 void D_WarpScreen (void)
43 {
44 	int		w, h;
45 	int		u,v, u2, v2;
46 	byte	*dest;
47 	int		*turb;
48 	int		*col;
49 	byte	**row;
50 
51 	static int	cached_width, cached_height;
52 	static byte	*rowptr[1200+AMP2*2];
53 	static int	column[1600+AMP2*2];
54 
55 	//
56 	// these are constant over resolutions, and can be saved
57 	//
58 	w = r_newrefdef.width;
59 	h = r_newrefdef.height;
60 	if (w != cached_width || h != cached_height)
61 	{
62 		cached_width = w;
63 		cached_height = h;
64 		for (v=0 ; v<h+AMP2*2 ; v++)
65 		{
66 			v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
67 			rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
68 		}
69 
70 		for (u=0 ; u<w+AMP2*2 ; u++)
71 		{
72 			u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
73 			column[u] = u2;
74 		}
75 	}
76 
77 	turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
78 	dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
79 
80 	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
81 	{
82 		col = &column[turb[v]];
83 		row = &rowptr[v];
84 		for (u=0 ; u<w ; u+=4)
85 		{
86 			dest[u+0] = row[turb[u+0]][col[u+0]];
87 			dest[u+1] = row[turb[u+1]][col[u+1]];
88 			dest[u+2] = row[turb[u+2]][col[u+2]];
89 			dest[u+3] = row[turb[u+3]][col[u+3]];
90 		}
91 	}
92 }
93 
94 
95 #if	!id386
96 
97 /*
98 =============
99 D_DrawTurbulent8Span
100 =============
101 */
D_DrawTurbulent8Span(void)102 void D_DrawTurbulent8Span (void)
103 {
104 	int		sturb, tturb;
105 
106 	do
107 	{
108 		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
109 		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
110 		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
111 		r_turb_s += r_turb_sstep;
112 		r_turb_t += r_turb_tstep;
113 	} while (--r_turb_spancount > 0);
114 }
115 
116 #endif	// !id386
117 
118 
119 /*
120 =============
121 Turbulent8
122 =============
123 */
Turbulent8(espan_t * pspan)124 void Turbulent8 (espan_t *pspan)
125 {
126 	int				count;
127 	fixed16_t		snext, tnext;
128 	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
129 	float			sdivz16stepu, tdivz16stepu, zi16stepu;
130 
131 	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
132 
133 	r_turb_sstep = 0;	// keep compiler happy
134 	r_turb_tstep = 0;	// ditto
135 
136 	r_turb_pbase = (unsigned char *)cacheblock;
137 
138 	sdivz16stepu = d_sdivzstepu * 16;
139 	tdivz16stepu = d_tdivzstepu * 16;
140 	zi16stepu = d_zistepu * 16;
141 
142 	do
143 	{
144 		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
145 				(r_screenwidth * pspan->v) + pspan->u);
146 
147 		count = pspan->count;
148 
149 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
150 		du = (float)pspan->u;
151 		dv = (float)pspan->v;
152 
153 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
154 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
155 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
156 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
157 
158 		r_turb_s = (int)(sdivz * z) + sadjust;
159 		if (r_turb_s > bbextents)
160 			r_turb_s = bbextents;
161 		else if (r_turb_s < 0)
162 			r_turb_s = 0;
163 
164 		r_turb_t = (int)(tdivz * z) + tadjust;
165 		if (r_turb_t > bbextentt)
166 			r_turb_t = bbextentt;
167 		else if (r_turb_t < 0)
168 			r_turb_t = 0;
169 
170 		do
171 		{
172 		// calculate s and t at the far end of the span
173 			if (count >= 16)
174 				r_turb_spancount = 16;
175 			else
176 				r_turb_spancount = count;
177 
178 			count -= r_turb_spancount;
179 
180 			if (count)
181 			{
182 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
183 			// calculate s and t steps across span by shifting
184 				sdivz += sdivz16stepu;
185 				tdivz += tdivz16stepu;
186 				zi += zi16stepu;
187 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
188 
189 				snext = (int)(sdivz * z) + sadjust;
190 				if (snext > bbextents)
191 					snext = bbextents;
192 				else if (snext < 16)
193 					snext = 16;	// prevent round-off error on <0 steps from
194 								//  from causing overstepping & running off the
195 								//  edge of the texture
196 
197 				tnext = (int)(tdivz * z) + tadjust;
198 				if (tnext > bbextentt)
199 					tnext = bbextentt;
200 				else if (tnext < 16)
201 					tnext = 16;	// guard against round-off error on <0 steps
202 
203 				r_turb_sstep = (snext - r_turb_s) >> 4;
204 				r_turb_tstep = (tnext - r_turb_t) >> 4;
205 			}
206 			else
207 			{
208 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
209 			// can't step off polygon), clamp, calculate s and t steps across
210 			// span by division, biasing steps low so we don't run off the
211 			// texture
212 				spancountminus1 = (float)(r_turb_spancount - 1);
213 				sdivz += d_sdivzstepu * spancountminus1;
214 				tdivz += d_tdivzstepu * spancountminus1;
215 				zi += d_zistepu * spancountminus1;
216 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
217 				snext = (int)(sdivz * z) + sadjust;
218 				if (snext > bbextents)
219 					snext = bbextents;
220 				else if (snext < 16)
221 					snext = 16;	// prevent round-off error on <0 steps from
222 								//  from causing overstepping & running off the
223 								//  edge of the texture
224 
225 				tnext = (int)(tdivz * z) + tadjust;
226 				if (tnext > bbextentt)
227 					tnext = bbextentt;
228 				else if (tnext < 16)
229 					tnext = 16;	// guard against round-off error on <0 steps
230 
231 				if (r_turb_spancount > 1)
232 				{
233 					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
234 					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
235 				}
236 			}
237 
238 			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
239 			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
240 
241 			D_DrawTurbulent8Span ();
242 
243 			r_turb_s = snext;
244 			r_turb_t = tnext;
245 
246 		} while (count > 0);
247 
248 	} while ((pspan = pspan->pnext) != NULL);
249 }
250 
251 //====================
252 //PGM
253 /*
254 =============
255 NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
256 	but the turbulence is automatically 0.
257 =============
258 */
NonTurbulent8(espan_t * pspan)259 void NonTurbulent8 (espan_t *pspan)
260 {
261 	int				count;
262 	fixed16_t		snext, tnext;
263 	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
264 	float			sdivz16stepu, tdivz16stepu, zi16stepu;
265 
266 //	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
267 	r_turb_turb = blanktable;
268 
269 	r_turb_sstep = 0;	// keep compiler happy
270 	r_turb_tstep = 0;	// ditto
271 
272 	r_turb_pbase = (unsigned char *)cacheblock;
273 
274 	sdivz16stepu = d_sdivzstepu * 16;
275 	tdivz16stepu = d_tdivzstepu * 16;
276 	zi16stepu = d_zistepu * 16;
277 
278 	do
279 	{
280 		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
281 				(r_screenwidth * pspan->v) + pspan->u);
282 
283 		count = pspan->count;
284 
285 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
286 		du = (float)pspan->u;
287 		dv = (float)pspan->v;
288 
289 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
290 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
291 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
292 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
293 
294 		r_turb_s = (int)(sdivz * z) + sadjust;
295 		if (r_turb_s > bbextents)
296 			r_turb_s = bbextents;
297 		else if (r_turb_s < 0)
298 			r_turb_s = 0;
299 
300 		r_turb_t = (int)(tdivz * z) + tadjust;
301 		if (r_turb_t > bbextentt)
302 			r_turb_t = bbextentt;
303 		else if (r_turb_t < 0)
304 			r_turb_t = 0;
305 
306 		do
307 		{
308 		// calculate s and t at the far end of the span
309 			if (count >= 16)
310 				r_turb_spancount = 16;
311 			else
312 				r_turb_spancount = count;
313 
314 			count -= r_turb_spancount;
315 
316 			if (count)
317 			{
318 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
319 			// calculate s and t steps across span by shifting
320 				sdivz += sdivz16stepu;
321 				tdivz += tdivz16stepu;
322 				zi += zi16stepu;
323 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
324 
325 				snext = (int)(sdivz * z) + sadjust;
326 				if (snext > bbextents)
327 					snext = bbextents;
328 				else if (snext < 16)
329 					snext = 16;	// prevent round-off error on <0 steps from
330 								//  from causing overstepping & running off the
331 								//  edge of the texture
332 
333 				tnext = (int)(tdivz * z) + tadjust;
334 				if (tnext > bbextentt)
335 					tnext = bbextentt;
336 				else if (tnext < 16)
337 					tnext = 16;	// guard against round-off error on <0 steps
338 
339 				r_turb_sstep = (snext - r_turb_s) >> 4;
340 				r_turb_tstep = (tnext - r_turb_t) >> 4;
341 			}
342 			else
343 			{
344 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
345 			// can't step off polygon), clamp, calculate s and t steps across
346 			// span by division, biasing steps low so we don't run off the
347 			// texture
348 				spancountminus1 = (float)(r_turb_spancount - 1);
349 				sdivz += d_sdivzstepu * spancountminus1;
350 				tdivz += d_tdivzstepu * spancountminus1;
351 				zi += d_zistepu * spancountminus1;
352 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
353 				snext = (int)(sdivz * z) + sadjust;
354 				if (snext > bbextents)
355 					snext = bbextents;
356 				else if (snext < 16)
357 					snext = 16;	// prevent round-off error on <0 steps from
358 								//  from causing overstepping & running off the
359 								//  edge of the texture
360 
361 				tnext = (int)(tdivz * z) + tadjust;
362 				if (tnext > bbextentt)
363 					tnext = bbextentt;
364 				else if (tnext < 16)
365 					tnext = 16;	// guard against round-off error on <0 steps
366 
367 				if (r_turb_spancount > 1)
368 				{
369 					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
370 					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
371 				}
372 			}
373 
374 			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
375 			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
376 
377 			D_DrawTurbulent8Span ();
378 
379 			r_turb_s = snext;
380 			r_turb_t = tnext;
381 
382 		} while (count > 0);
383 
384 	} while ((pspan = pspan->pnext) != NULL);
385 }
386 //PGM
387 //====================
388 
389 
390 #if	!id386
391 
392 /*
393 =============
394 D_DrawSpans16
395 
396   FIXME: actually make this subdivide by 16 instead of 8!!!
397 =============
398 */
D_DrawSpans16(espan_t * pspan)399 void D_DrawSpans16 (espan_t *pspan)
400 {
401 	int				count, spancount;
402 	unsigned char	*pbase, *pdest;
403 	fixed16_t		s, t, snext, tnext, sstep, tstep;
404 	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
405 	float			sdivz8stepu, tdivz8stepu, zi8stepu;
406 
407 	sstep = 0;	// keep compiler happy
408 	tstep = 0;	// ditto
409 
410 	pbase = (unsigned char *)cacheblock;
411 
412 	sdivz8stepu = d_sdivzstepu * 8;
413 	tdivz8stepu = d_tdivzstepu * 8;
414 	zi8stepu = d_zistepu * 8;
415 
416 	do
417 	{
418 		pdest = (unsigned char *)((byte *)d_viewbuffer +
419 				(r_screenwidth * pspan->v) + pspan->u);
420 
421 		count = pspan->count;
422 
423 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
424 		du = (float)pspan->u;
425 		dv = (float)pspan->v;
426 
427 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
428 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
429 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
430 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
431 
432 		s = (int)(sdivz * z) + sadjust;
433 		if (s > bbextents)
434 			s = bbextents;
435 		else if (s < 0)
436 			s = 0;
437 
438 		t = (int)(tdivz * z) + tadjust;
439 		if (t > bbextentt)
440 			t = bbextentt;
441 		else if (t < 0)
442 			t = 0;
443 
444 		do
445 		{
446 		// calculate s and t at the far end of the span
447 			if (count >= 8)
448 				spancount = 8;
449 			else
450 				spancount = count;
451 
452 			count -= spancount;
453 
454 			if (count)
455 			{
456 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
457 			// calculate s and t steps across span by shifting
458 				sdivz += sdivz8stepu;
459 				tdivz += tdivz8stepu;
460 				zi += zi8stepu;
461 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
462 
463 				snext = (int)(sdivz * z) + sadjust;
464 				if (snext > bbextents)
465 					snext = bbextents;
466 				else if (snext < 8)
467 					snext = 8;	// prevent round-off error on <0 steps from
468 								//  from causing overstepping & running off the
469 								//  edge of the texture
470 
471 				tnext = (int)(tdivz * z) + tadjust;
472 				if (tnext > bbextentt)
473 					tnext = bbextentt;
474 				else if (tnext < 8)
475 					tnext = 8;	// guard against round-off error on <0 steps
476 
477 				sstep = (snext - s) >> 3;
478 				tstep = (tnext - t) >> 3;
479 			}
480 			else
481 			{
482 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
483 			// can't step off polygon), clamp, calculate s and t steps across
484 			// span by division, biasing steps low so we don't run off the
485 			// texture
486 				spancountminus1 = (float)(spancount - 1);
487 				sdivz += d_sdivzstepu * spancountminus1;
488 				tdivz += d_tdivzstepu * spancountminus1;
489 				zi += d_zistepu * spancountminus1;
490 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
491 				snext = (int)(sdivz * z) + sadjust;
492 				if (snext > bbextents)
493 					snext = bbextents;
494 				else if (snext < 8)
495 					snext = 8;	// prevent round-off error on <0 steps from
496 								//  from causing overstepping & running off the
497 								//  edge of the texture
498 
499 				tnext = (int)(tdivz * z) + tadjust;
500 				if (tnext > bbextentt)
501 					tnext = bbextentt;
502 				else if (tnext < 8)
503 					tnext = 8;	// guard against round-off error on <0 steps
504 
505 				if (spancount > 1)
506 				{
507 					sstep = (snext - s) / (spancount - 1);
508 					tstep = (tnext - t) / (spancount - 1);
509 				}
510 			}
511 
512 			do
513 			{
514 				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
515 				s += sstep;
516 				t += tstep;
517 			} while (--spancount > 0);
518 
519 			s = snext;
520 			t = tnext;
521 
522 		} while (count > 0);
523 
524 	} while ((pspan = pspan->pnext) != NULL);
525 }
526 
527 #endif
528 
529 
530 #if	!id386
531 
532 /*
533 =============
534 D_DrawZSpans
535 =============
536 */
D_DrawZSpans(espan_t * pspan)537 void D_DrawZSpans (espan_t *pspan)
538 {
539 	int				count, doublecount, izistep;
540 	int				izi;
541 	short			*pdest;
542 	unsigned		ltemp;
543 	float			zi;
544 	float			du, dv;
545 
546 // FIXME: check for clamping/range problems
547 // we count on FP exceptions being turned off to avoid range problems
548 	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
549 
550 	do
551 	{
552 		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
553 
554 		count = pspan->count;
555 
556 	// calculate the initial 1/z
557 		du = (float)pspan->u;
558 		dv = (float)pspan->v;
559 
560 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
561 	// we count on FP exceptions being turned off to avoid range problems
562 		izi = (int)(zi * 0x8000 * 0x10000);
563 
564 		if ((long)pdest & 0x02)
565 		{
566 			*pdest++ = (short)(izi >> 16);
567 			izi += izistep;
568 			count--;
569 		}
570 
571 		if ((doublecount = count >> 1) > 0)
572 		{
573 			do
574 			{
575 				ltemp = izi >> 16;
576 				izi += izistep;
577 				ltemp |= izi & 0xFFFF0000;
578 				izi += izistep;
579 				*(int *)pdest = ltemp;
580 				pdest += 2;
581 			} while (--doublecount > 0);
582 		}
583 
584 		if (count & 1)
585 			*pdest = (short)(izi >> 16);
586 
587 	} while ((pspan = pspan->pnext) != NULL);
588 }
589 
590 #endif
591 
592