2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // d_sprite.c: software top-level rasterization driver module for drawing
26 static int sprite_height
;
27 static int minindex
, maxindex
;
28 static sspan_t
*sprite_spans
;
37 void D_SpriteDrawSpans (sspan_t
*pspan
)
39 int count
, spancount
, izistep
;
42 fixed16_t s
, t
, snext
, tnext
, sstep
, tstep
;
43 float sdivz
, tdivz
, zi
, z
, du
, dv
, spancountminus1
;
44 float sdivz8stepu
, tdivz8stepu
, zi8stepu
;
48 sstep
= 0; // keep compiler happy
53 sdivz8stepu
= d_sdivzstepu
* 8;
54 tdivz8stepu
= d_tdivzstepu
* 8;
55 zi8stepu
= d_zistepu
* 8;
57 // we count on FP exceptions being turned off to avoid range problems
58 izistep
= (int)(d_zistepu
* 0x8000 * 0x10000);
62 pdest
= (byte
*)d_viewbuffer
+ (screenwidth
* pspan
->v
) + pspan
->u
;
63 pz
= d_pzbuffer
+ (d_zwidth
* pspan
->v
) + pspan
->u
;
70 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
74 sdivz
= d_sdivzorigin
+ dv
*d_sdivzstepv
+ du
*d_sdivzstepu
;
75 tdivz
= d_tdivzorigin
+ dv
*d_tdivzstepv
+ du
*d_tdivzstepu
;
76 zi
= d_ziorigin
+ dv
*d_zistepv
+ du
*d_zistepu
;
77 z
= (float)0x10000 / zi
; // prescale to 16.16 fixed-point
78 // we count on FP exceptions being turned off to avoid range problems
79 izi
= (int)(zi
* 0x8000 * 0x10000);
81 s
= (int)(sdivz
* z
) + sadjust
;
87 t
= (int)(tdivz
* z
) + tadjust
;
95 // calculate s and t at the far end of the span
105 // calculate s/z, t/z, zi->fixed s and t at far end of span,
106 // calculate s and t steps across span by shifting
107 sdivz
+= sdivz8stepu
;
108 tdivz
+= tdivz8stepu
;
110 z
= (float)0x10000 / zi
; // prescale to 16.16 fixed-point
112 snext
= (int)(sdivz
* z
) + sadjust
;
113 if (snext
> bbextents
)
116 snext
= 8; // prevent round-off error on <0 steps from
117 // from causing overstepping & running off the
118 // edge of the texture
120 tnext
= (int)(tdivz
* z
) + tadjust
;
121 if (tnext
> bbextentt
)
124 tnext
= 8; // guard against round-off error on <0 steps
126 sstep
= (snext
- s
) >> 3;
127 tstep
= (tnext
- t
) >> 3;
131 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
132 // can't step off polygon), clamp, calculate s and t steps across
133 // span by division, biasing steps low so we don't run off the
135 spancountminus1
= (float)(spancount
- 1);
136 sdivz
+= d_sdivzstepu
* spancountminus1
;
137 tdivz
+= d_tdivzstepu
* spancountminus1
;
138 zi
+= d_zistepu
* spancountminus1
;
139 z
= (float)0x10000 / zi
; // prescale to 16.16 fixed-point
140 snext
= (int)(sdivz
* z
) + sadjust
;
141 if (snext
> bbextents
)
144 snext
= 8; // prevent round-off error on <0 steps from
145 // from causing overstepping & running off the
146 // edge of the texture
148 tnext
= (int)(tdivz
* z
) + tadjust
;
149 if (tnext
> bbextentt
)
152 tnext
= 8; // guard against round-off error on <0 steps
156 sstep
= (snext
- s
) / (spancount
- 1);
157 tstep
= (tnext
- t
) / (spancount
- 1);
163 btemp
= *(pbase
+ (s
>> 16) + (t
>> 16) * cachewidth
);
166 if (*pz
<= (izi
>> 16))
178 } while (--spancount
> 0);
188 } while (pspan
->count
!= DS_SPAN_LIST_END
);
195 =====================
197 =====================
199 void D_SpriteScanLeftEdge (void)
201 int i
, v
, itop
, ibottom
, lmaxindex
;
202 emitpoint_t
*pvert
, *pnext
;
204 float du
, dv
, vtop
, vbottom
, slope
;
207 pspan
= sprite_spans
;
210 i
= r_spritedesc
.nump
;
212 lmaxindex
= maxindex
;
214 lmaxindex
= r_spritedesc
.nump
;
216 vtop
= ceilf (r_spritedesc
.pverts
[i
].v
);
220 pvert
= &r_spritedesc
.pverts
[i
];
223 vbottom
= ceilf (pnext
->v
);
227 du
= pnext
->u
- pvert
->u
;
228 dv
= pnext
->v
- pvert
->v
;
230 u_step
= (int)(slope
* 0x10000);
231 // adjust u to ceil the integer portion
232 u
= (int)((pvert
->u
+ (slope
* (vtop
- pvert
->v
))) * 0x10000) +
235 ibottom
= (int)vbottom
;
237 for (v
=itop
; v
<ibottom
; v
++)
250 i
= r_spritedesc
.nump
;
252 } while (i
!= lmaxindex
);
257 =====================
258 D_SpriteScanRightEdge
259 =====================
261 void D_SpriteScanRightEdge (void)
263 int i
, v
, itop
, ibottom
;
264 emitpoint_t
*pvert
, *pnext
;
266 float du
, dv
, vtop
, vbottom
, slope
, uvert
, unext
, vvert
, vnext
;
269 pspan
= sprite_spans
;
272 vvert
= r_spritedesc
.pverts
[i
].v
;
273 if (vvert
< r_refdef
.fvrecty_adj
)
274 vvert
= r_refdef
.fvrecty_adj
;
275 if (vvert
> r_refdef
.fvrectbottom_adj
)
276 vvert
= r_refdef
.fvrectbottom_adj
;
278 vtop
= ceilf (vvert
);
282 pvert
= &r_spritedesc
.pverts
[i
];
286 if (vnext
< r_refdef
.fvrecty_adj
)
287 vnext
= r_refdef
.fvrecty_adj
;
288 if (vnext
> r_refdef
.fvrectbottom_adj
)
289 vnext
= r_refdef
.fvrectbottom_adj
;
291 vbottom
= ceilf (vnext
);
296 if (uvert
< r_refdef
.fvrectx_adj
)
297 uvert
= r_refdef
.fvrectx_adj
;
298 if (uvert
> r_refdef
.fvrectright_adj
)
299 uvert
= r_refdef
.fvrectright_adj
;
302 if (unext
< r_refdef
.fvrectx_adj
)
303 unext
= r_refdef
.fvrectx_adj
;
304 if (unext
> r_refdef
.fvrectright_adj
)
305 unext
= r_refdef
.fvrectright_adj
;
310 u_step
= (int)(slope
* 0x10000);
311 // adjust u to ceil the integer portion
312 u
= (int)((uvert
+ (slope
* (vtop
- vvert
))) * 0x10000) +
315 ibottom
= (int)vbottom
;
317 for (v
=itop
; v
<ibottom
; v
++)
319 pspan
->count
= (u
>> 16) - pspan
->u
;
329 if (i
== r_spritedesc
.nump
)
332 } while (i
!= maxindex
);
334 pspan
->count
= DS_SPAN_LIST_END
; // mark the end of the span list
339 =====================
340 D_SpriteCalculateGradients
341 =====================
343 void D_SpriteCalculateGradients (void)
345 vec3_t p_normal
, p_saxis
, p_taxis
, p_temp1
;
348 TransformVector (r_spritedesc
.vpn
, p_normal
);
349 TransformVector (r_spritedesc
.vright
, p_saxis
);
350 TransformVector (r_spritedesc
.vup
, p_taxis
);
351 VectorInverse (p_taxis
);
353 distinv
= 1.0 / (-DotProduct (modelorg
, r_spritedesc
.vpn
));
355 d_sdivzstepu
= p_saxis
[0] * xscaleinv
;
356 d_tdivzstepu
= p_taxis
[0] * xscaleinv
;
358 d_sdivzstepv
= -p_saxis
[1] * yscaleinv
;
359 d_tdivzstepv
= -p_taxis
[1] * yscaleinv
;
361 d_zistepu
= p_normal
[0] * xscaleinv
* distinv
;
362 d_zistepv
= -p_normal
[1] * yscaleinv
* distinv
;
364 d_sdivzorigin
= p_saxis
[2] - xcenter
* d_sdivzstepu
-
365 ycenter
* d_sdivzstepv
;
366 d_tdivzorigin
= p_taxis
[2] - xcenter
* d_tdivzstepu
-
367 ycenter
* d_tdivzstepv
;
368 d_ziorigin
= p_normal
[2] * distinv
- xcenter
* d_zistepu
-
371 TransformVector (modelorg
, p_temp1
);
373 sadjust
= ((fixed16_t
)(DotProduct (p_temp1
, p_saxis
) * 0x10000 + 0.5)) -
374 (-(cachewidth
>> 1) << 16);
375 tadjust
= ((fixed16_t
)(DotProduct (p_temp1
, p_taxis
) * 0x10000 + 0.5)) -
376 (-(sprite_height
>> 1) << 16);
378 // -1 (-epsilon) so we never wander off the edge of the texture
379 bbextents
= (cachewidth
<< 16) - 1;
380 bbextentt
= (sprite_height
<< 16) - 1;
385 =====================
387 =====================
389 void D_DrawSprite (void)
394 sspan_t spans
[MAXHEIGHT
+1];
396 sprite_spans
= spans
;
398 // find the top and bottom vertices, and make sure there's at least one scan to
402 pverts
= r_spritedesc
.pverts
;
404 for (i
=0 ; i
<r_spritedesc
.nump
; i
++)
406 if (pverts
->v
< ymin
)
412 if (pverts
->v
> ymax
)
425 return; // doesn't cross any scans at all
427 cachewidth
= r_spritedesc
.pspriteframe
->width
;
428 sprite_height
= r_spritedesc
.pspriteframe
->height
;
429 cacheblock
= (byte
*)&r_spritedesc
.pspriteframe
->pixels
[0];
431 // copy the first vertex to the last vertex, so we don't have to deal with
433 nump
= r_spritedesc
.nump
;
434 pverts
= r_spritedesc
.pverts
;
435 pverts
[nump
] = pverts
[0];
437 D_SpriteCalculateGradients ();
438 D_SpriteScanLeftEdge ();
439 D_SpriteScanRightEdge ();
440 D_SpriteDrawSpans (sprite_spans
);