1 /*
2 * d_scan.c - Portable C scan-level rasterization code, all pixel depths.
3 * $Id: d_scan.c 5976 2017-09-16 20:03:22Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 1997-1998 Raven Software Corp.
7 * C versions of several asm functions: Juraj Styk <jurajstyk@host.sk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 * See the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "quakedef.h"
26 #include "r_local.h"
27 #include "d_local.h"
28
29 ASM_LINKAGE_BEGIN
30 unsigned char *r_turb_pbase, *r_turb_pdest;
31 fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
32 int *r_turb_turb;
33 int r_turb_spancount;
34 byte scanList[SCAN_SIZE];
35 int ZScanCount;
36 ASM_LINKAGE_END
37
38
39 /*
40 =============
41 D_WarpScreen
42
43 // this performs a slight compression of the screen at the same time as
44 // the sine warp, to keep the edges from wrapping
45 =============
46 */
D_WarpScreen(void)47 void D_WarpScreen (void)
48 {
49 int w, h;
50 int u, v;
51 byte *dest;
52 int *turb;
53 int *col;
54 byte **row;
55 byte *rowptr[MAXHEIGHT+(AMP2*2)];
56 int column[MAXWIDTH+(AMP2*2)];
57 float wratio, hratio;
58
59 w = r_refdef.vrect.width;
60 h = r_refdef.vrect.height;
61
62 wratio = w / (float)scr_vrect.width;
63 hratio = h / (float)scr_vrect.height;
64
65 for (v = 0; v < scr_vrect.height + AMP2*2; v++)
66 {
67 rowptr[v] = d_viewbuffer + (r_refdef.vrect.y * screenwidth) +
68 (screenwidth * (int)((float)v * hratio * h / (h + AMP2 * 2)));
69 }
70
71 for (u = 0; u < scr_vrect.width + AMP2*2; u++)
72 {
73 column[u] = r_refdef.vrect.x +
74 (int)((float)u * wratio * w / (w + AMP2 * 2));
75 }
76
77 turb = intsintable + ((int)(cl.time*SPEED) & (CYCLE-1));
78 dest = vid.buffer + scr_vrect.y * vid.rowbytes + scr_vrect.x;
79
80 for (v = 0; v < scr_vrect.height; v++, dest += vid.rowbytes)
81 {
82 col = &column[turb[v]];
83 row = &rowptr[v];
84
85 for (u = 0; u < scr_vrect.width; u += 4)
86 {
87 dest[u+0] = row[turb[u+0]][col[u+0]];
88 dest[u+1] = row[turb[u+1]][col[u+1]];
89 dest[u+2] = row[turb[u+2]][col[u+2]];
90 dest[u+3] = row[turb[u+3]][col[u+3]];
91 }
92 }
93 }
94
95
96 #if !id386
97 /*
98 =============
99 D_DrawTurbulent8Span
100 =============
101 */
102 #if !id68k
D_DrawTurbulent8Span(void)103 static void D_DrawTurbulent8Span (void)
104 {
105 int sturb, tturb;
106
107 do
108 {
109 sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
110 tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
111 *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
112 r_turb_s += r_turb_sstep;
113 r_turb_t += r_turb_tstep;
114 } while (--r_turb_spancount > 0);
115 }
116 #endif
117
D_DrawTurbulent8TSpan(void)118 static void D_DrawTurbulent8TSpan (void)
119 {
120 int sturb, tturb;
121 unsigned char temp;
122
123 do
124 {
125 sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
126 tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
127
128 if (scanList[r_turb_spancount-1] == 1)
129 {
130 temp = *(r_turb_pbase + (tturb<<6) + sturb);
131 *r_turb_pdest = mainTransTable[(temp<<8) + (*r_turb_pdest)];
132 r_turb_pdest++;
133 }
134 else
135 r_turb_pdest++;
136
137 r_turb_s += r_turb_sstep;
138 r_turb_t += r_turb_tstep;
139 } while (--r_turb_spancount > 0);
140 }
141
D_DrawTurbulent8TQuickSpan(void)142 static void D_DrawTurbulent8TQuickSpan (void)
143 {
144 int sturb, tturb;
145 unsigned char temp;
146
147 do
148 {
149 sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
150 tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
151 temp = *(r_turb_pbase + (tturb<<6) + sturb);
152 *r_turb_pdest = mainTransTable[(temp<<8) + (*r_turb_pdest)];
153 r_turb_pdest++;
154 r_turb_s += r_turb_sstep;
155 r_turb_t += r_turb_tstep;
156 } while (--r_turb_spancount > 0);
157 }
158
159 #endif /* !id386 */
160
161
162 /*
163 =============
164 Turbulent8
165 =============
166 */
Turbulent8(surf_t * s)167 void Turbulent8 (surf_t *s)
168 {
169 int count;
170 fixed16_t snext, tnext;
171 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
172 float sdivz16stepu, tdivz16stepu, zi16stepu;
173 byte origscanList[SCAN_SIZE];
174 espan_t *pspan;
175
176 pspan = s->spans;
177
178 r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
179
180 r_turb_sstep = 0; // keep compiler happy
181 r_turb_tstep = 0; // ditto
182
183 r_turb_pbase = (unsigned char *)cacheblock;
184
185 sdivz16stepu = d_sdivzstepu * 16;
186 tdivz16stepu = d_tdivzstepu * 16;
187 zi16stepu = d_zistepu * 16;
188
189 do
190 {
191 r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u);
192 count = pspan->count;
193
194 if (r_transwater.integer && s->flags & SURF_TRANSLUCENT)
195 {
196 D_DrawSingleZSpans(pspan);
197 if (ZScanCount == count) // fully blocked
198 continue;
199
200 if (ZScanCount)
201 memcpy(origscanList,scanList,count);
202 }
203
204 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
205 du = (float)pspan->u;
206 dv = (float)pspan->v;
207
208 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
209 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
210 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
211 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
212
213 r_turb_s = (int)(sdivz * z) + sadjust;
214 if (r_turb_s > bbextents)
215 r_turb_s = bbextents;
216 else if (r_turb_s < 0)
217 r_turb_s = 0;
218
219 r_turb_t = (int)(tdivz * z) + tadjust;
220 if (r_turb_t > bbextentt)
221 r_turb_t = bbextentt;
222 else if (r_turb_t < 0)
223 r_turb_t = 0;
224
225 do
226 {
227 // calculate s and t at the far end of the span
228 if (count >= 16)
229 {
230 r_turb_spancount = 16;
231 }
232 else
233 r_turb_spancount = count;
234
235 count -= r_turb_spancount;
236
237 if (count)
238 {
239 // calculate s/z, t/z, zi->fixed s and t at far end of span,
240 // calculate s and t steps across span by shifting
241 sdivz += sdivz16stepu;
242 tdivz += tdivz16stepu;
243 zi += zi16stepu;
244 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
245
246 snext = (int)(sdivz * z) + sadjust;
247 if (snext > bbextents)
248 snext = bbextents;
249 else if (snext < 16)
250 snext = 16; // prevent round-off error on <0 steps from
251 // from causing overstepping & running off the
252 // edge of the texture
253
254 tnext = (int)(tdivz * z) + tadjust;
255 if (tnext > bbextentt)
256 tnext = bbextentt;
257 else if (tnext < 16)
258 tnext = 16; // guard against round-off error on <0 steps
259
260 r_turb_sstep = (snext - r_turb_s) >> 4;
261 r_turb_tstep = (tnext - r_turb_t) >> 4;
262 }
263 else
264 {
265 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
266 // can't step off polygon), clamp, calculate s and t steps across
267 // span by division, biasing steps low so we don't run off the
268 // texture
269 spancountminus1 = (float)(r_turb_spancount - 1);
270 sdivz += d_sdivzstepu * spancountminus1;
271 tdivz += d_tdivzstepu * spancountminus1;
272 zi += d_zistepu * spancountminus1;
273 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
274 snext = (int)(sdivz * z) + sadjust;
275 if (snext > bbextents)
276 snext = bbextents;
277 else if (snext < 16)
278 snext = 16; // prevent round-off error on <0 steps from
279 // from causing overstepping & running off the
280 // edge of the texture
281
282 tnext = (int)(tdivz * z) + tadjust;
283 if (tnext > bbextentt)
284 tnext = bbextentt;
285 else if (tnext < 16)
286 tnext = 16; // guard against round-off error on <0 steps
287
288 if (r_turb_spancount > 1)
289 {
290 r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
291 r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
292 }
293 }
294
295 r_turb_s = r_turb_s & ((CYCLE<<16)-1);
296 r_turb_t = r_turb_t & ((CYCLE<<16)-1);
297
298 if (r_transwater.integer && s->flags & SURF_TRANSLUCENT)
299 {
300 if (ZScanCount)
301 {
302 memcpy(scanList,&origscanList[count],r_turb_spancount);
303 D_DrawTurbulent8TSpan ();
304 }
305 else
306 D_DrawTurbulent8TQuickSpan ();
307 }
308 else
309 D_DrawTurbulent8Span ();
310
311 r_turb_s = snext;
312 r_turb_t = tnext;
313
314 } while (count > 0);
315
316 } while ((pspan = pspan->pnext) != NULL);
317 }
318
319
320 #if !id386
321
322 /*
323 =============
324 D_DrawSpans8
325 =============
326 */
327 #if !id68k
D_DrawSpans8(espan_t * pspan)328 void D_DrawSpans8 (espan_t *pspan)
329 {
330 int count, spancount;
331 unsigned char *pbase, *pdest;
332 fixed16_t s, t, snext, tnext, sstep, tstep;
333 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
334 float sdivz8stepu, tdivz8stepu, zi8stepu;
335
336 sstep = 0; // keep compiler happy
337 tstep = 0; // ditto
338
339 pbase = (unsigned char *)cacheblock;
340
341 sdivz8stepu = d_sdivzstepu * 8;
342 tdivz8stepu = d_tdivzstepu * 8;
343 zi8stepu = d_zistepu * 8;
344
345 do
346 {
347 pdest = (unsigned char *)((byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u);
348 count = pspan->count;
349
350 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
351 du = (float)pspan->u;
352 dv = (float)pspan->v;
353
354 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
355 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
356 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
357 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
358
359 s = (int)(sdivz * z) + sadjust;
360 if (s > bbextents)
361 s = bbextents;
362 else if (s < 0)
363 s = 0;
364
365 t = (int)(tdivz * z) + tadjust;
366 if (t > bbextentt)
367 t = bbextentt;
368 else if (t < 0)
369 t = 0;
370
371 do
372 {
373 // calculate s and t at the far end of the span
374 if (count >= 8)
375 spancount = 8;
376 else
377 spancount = count;
378
379 count -= spancount;
380
381 if (count)
382 {
383 // calculate s/z, t/z, zi->fixed s and t at far end of span,
384 // calculate s and t steps across span by shifting
385 sdivz += sdivz8stepu;
386 tdivz += tdivz8stepu;
387 zi += zi8stepu;
388 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
389
390 snext = (int)(sdivz * z) + sadjust;
391 if (snext > bbextents)
392 snext = bbextents;
393 else if (snext < 8)
394 snext = 8; // prevent round-off error on <0 steps from
395 // from causing overstepping & running off the
396 // edge of the texture
397
398 tnext = (int)(tdivz * z) + tadjust;
399 if (tnext > bbextentt)
400 tnext = bbextentt;
401 else if (tnext < 8)
402 tnext = 8; // guard against round-off error on <0 steps
403
404 sstep = (snext - s) >> 3;
405 tstep = (tnext - t) >> 3;
406 }
407 else
408 {
409 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
410 // can't step off polygon), clamp, calculate s and t steps across
411 // span by division, biasing steps low so we don't run off the
412 // texture
413 spancountminus1 = (float)(spancount - 1);
414 sdivz += d_sdivzstepu * spancountminus1;
415 tdivz += d_tdivzstepu * spancountminus1;
416 zi += d_zistepu * spancountminus1;
417 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
418 snext = (int)(sdivz * z) + sadjust;
419 if (snext > bbextents)
420 snext = bbextents;
421 else if (snext < 8)
422 snext = 8; // prevent round-off error on <0 steps from
423 // from causing overstepping & running off the
424 // edge of the texture
425
426 tnext = (int)(tdivz * z) + tadjust;
427 if (tnext > bbextentt)
428 tnext = bbextentt;
429 else if (tnext < 8)
430 tnext = 8; // guard against round-off error on <0 steps
431
432 if (spancount > 1)
433 {
434 sstep = (snext - s) / (spancount - 1);
435 tstep = (tnext - t) / (spancount - 1);
436 }
437 }
438
439 do
440 {
441 *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
442 s += sstep;
443 t += tstep;
444 } while (--spancount > 0);
445
446 s = snext;
447 t = tnext;
448
449 } while (count > 0);
450
451 } while ((pspan = pspan->pnext) != NULL);
452 }
453 #endif /* !id68k */
454
D_DrawSpans8T(espan_t * pspan)455 void D_DrawSpans8T (espan_t *pspan)
456 {
457 int count, spancount;
458 unsigned char *pbase, *pdest;
459 fixed16_t s, t, snext, tnext, sstep, tstep;
460 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
461 float sdivz8stepu, tdivz8stepu, zi8stepu;
462 short *pz;
463 byte btemp;
464 int izi, izistep;
465
466 sstep = 0; // keep compiler happy
467 tstep = 0; // ditto
468
469 pbase = (unsigned char *)cacheblock;
470
471 sdivz8stepu = d_sdivzstepu * 8;
472 tdivz8stepu = d_tdivzstepu * 8;
473 zi8stepu = d_zistepu * 8;
474
475 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
476
477 do
478 {
479 pdest = (unsigned char *)((byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u);
480 pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
481 count = pspan->count;
482
483 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
484 du = (float)pspan->u;
485 dv = (float)pspan->v;
486
487 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
488 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
489 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
490 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
491 izi = (int)(zi * 0x8000 * 0x10000);
492
493 s = (int)(sdivz * z) + sadjust;
494 if (s > bbextents)
495 s = bbextents;
496 else if (s < 0)
497 s = 0;
498
499 t = (int)(tdivz * z) + tadjust;
500 if (t > bbextentt)
501 t = bbextentt;
502 else if (t < 0)
503 t = 0;
504
505 do
506 {
507 // calculate s and t at the far end of the span
508 if (count >= 8)
509 spancount = 8;
510 else
511 spancount = count;
512
513 count -= spancount;
514
515 if (count)
516 {
517 // calculate s/z, t/z, zi->fixed s and t at far end of span,
518 // calculate s and t steps across span by shifting
519 sdivz += sdivz8stepu;
520 tdivz += tdivz8stepu;
521 zi += zi8stepu;
522 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
523
524 snext = (int)(sdivz * z) + sadjust;
525 if (snext > bbextents)
526 snext = bbextents;
527 else if (snext < 8)
528 snext = 8; // prevent round-off error on <0 steps from
529 // from causing overstepping & running off the
530 // edge of the texture
531
532 tnext = (int)(tdivz * z) + tadjust;
533 if (tnext > bbextentt)
534 tnext = bbextentt;
535 else if (tnext < 8)
536 tnext = 8; // guard against round-off error on <0 steps
537
538 sstep = (snext - s) >> 3;
539 tstep = (tnext - t) >> 3;
540 }
541 else
542 {
543 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
544 // can't step off polygon), clamp, calculate s and t steps across
545 // span by division, biasing steps low so we don't run off the
546 // texture
547 spancountminus1 = (float)(spancount - 1);
548 sdivz += d_sdivzstepu * spancountminus1;
549 tdivz += d_tdivzstepu * spancountminus1;
550 zi += d_zistepu * spancountminus1;
551 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
552 snext = (int)(sdivz * z) + sadjust;
553 if (snext > bbextents)
554 snext = bbextents;
555 else if (snext < 8)
556 snext = 8; // prevent round-off error on <0 steps from
557 // from causing overstepping & running off the
558 // edge of the texture
559
560 tnext = (int)(tdivz * z) + tadjust;
561 if (tnext > bbextentt)
562 tnext = bbextentt;
563 else if (tnext < 8)
564 tnext = 8; // guard against round-off error on <0 steps
565
566 if (spancount > 1)
567 {
568 sstep = (snext - s) / (spancount - 1);
569 tstep = (tnext - t) / (spancount - 1);
570 }
571 }
572
573 do
574 {
575 btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
576 if (*pz <= (izi >> 16))
577 {
578 *pdest = mainTransTable[(btemp<<8) + (*pdest)];
579 }
580 izi += izistep;
581 pdest++;
582 pz++;
583
584 // *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
585 s += sstep;
586 t += tstep;
587 } while (--spancount > 0);
588
589 s = snext;
590 t = tnext;
591
592 } while (count > 0);
593
594 } while ((pspan = pspan->pnext) != NULL);
595 }
596
597 /*
598 =============
599 D_DrawZSpans
600 =============
601 */
602 #if !id68k
D_DrawZSpans(espan_t * pspan)603 void D_DrawZSpans (espan_t *pspan)
604 {
605 int count, doublecount, izistep;
606 int izi;
607 short *pdest;
608 unsigned int ltemp;
609 double zi;
610 float du, dv;
611
612 // FIXME: check for clamping/range problems
613 // we count on FP exceptions being turned off to avoid range problems
614 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
615
616 do
617 {
618 pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
619
620 count = pspan->count;
621
622 // calculate the initial 1/z
623 du = (float)pspan->u;
624 dv = (float)pspan->v;
625
626 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
627 // we count on FP exceptions being turned off to avoid range problems
628 izi = (int)(zi * 0x8000 * 0x10000);
629
630 if ((intptr_t)pdest & 0x02)
631 {
632 *pdest++ = (short)(izi >> 16);
633 izi += izistep;
634 count--;
635 }
636
637 if ((doublecount = count >> 1) > 0)
638 {
639 do
640 {
641 ltemp = izi >> 16;
642 izi += izistep;
643 ltemp |= izi & 0xFFFF0000;
644 izi += izistep;
645 *(int *)pdest = ltemp;
646 pdest += 2;
647 } while (--doublecount > 0);
648 }
649
650 if (count & 1)
651 *pdest = (short)(izi >> 16);
652
653 } while ((pspan = pspan->pnext) != NULL);
654 }
655 #endif /* !id68k */
656
657 /*
658 =============
659 D_DrawSingleZSpans
660 =============
661 */
D_DrawSingleZSpans(espan_t * pspan)662 void D_DrawSingleZSpans (espan_t *pspan)
663 {
664 int count, izistep;
665 int izi;
666 short *pdest;
667 float zi;
668 float du, dv;
669
670 ZScanCount = 0;
671
672 // FIXME: check for clamping/range problems
673 // we count on FP exceptions being turned off to avoid range problems
674 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
675
676 pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
677
678 count = pspan->count;
679
680 // calculate the initial 1/z
681 du = (float)pspan->u;
682 dv = (float)pspan->v;
683
684 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
685 // we count on FP exceptions being turned off to avoid range problems
686 izi = (int)(zi * 0x8000 * 0x10000);
687
688 if (count > 0)
689 {
690 do
691 {
692 if (*pdest > (short)(izi >> 16))
693 {
694 ZScanCount++;
695 scanList[count-1] = 0;
696 }
697 else
698 {
699 scanList[count-1] = 1;
700 *pdest = (short)(izi >> 16);
701 }
702 izi += izistep;
703 pdest++;
704 count--;
705 } while (count > 0);
706 }
707 }
708
709 #endif /* !id386 */
710
711