• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_sprite.c: software top-level rasterization driver module for drawing
21 // sprites
22 
23 #include "quakedef.h"
24 #include "d_local.h"
25 
26 static int		sprite_height;
27 static int		minindex, maxindex;
28 static sspan_t	*sprite_spans;
29 
30 #if	!id386
31 
32 /*
33 =====================
34 D_SpriteDrawSpans
35 =====================
36 */
D_SpriteDrawSpans(sspan_t * pspan)37 void D_SpriteDrawSpans (sspan_t *pspan)
38 {
39 	int			count, spancount, izistep;
40 	int			izi;
41 	byte		*pbase, *pdest;
42 	fixed16_t	s, t, snext, tnext, sstep, tstep;
43 	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
44 	float		sdivz8stepu, tdivz8stepu, zi8stepu;
45 	byte		btemp;
46 	short		*pz;
47 
48 	sstep = 0;	// keep compiler happy
49 	tstep = 0;	// ditto
50 
51 	pbase = cacheblock;
52 
53 	sdivz8stepu = d_sdivzstepu * 8;
54 	tdivz8stepu = d_tdivzstepu * 8;
55 	zi8stepu = d_zistepu * 8;
56 
57 // we count on FP exceptions being turned off to avoid range problems
58 	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
59 
60 	do
61 	{
62 		pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
63 		pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
64 
65 		count = pspan->count;
66 
67 		if (count <= 0)
68 			goto NextSpan;
69 
70 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
71 		du = (float)pspan->u;
72 		dv = (float)pspan->v;
73 
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);
80 
81 		s = (int)(sdivz * z) + sadjust;
82 		if (s > bbextents)
83 			s = bbextents;
84 		else if (s < 0)
85 			s = 0;
86 
87 		t = (int)(tdivz * z) + tadjust;
88 		if (t > bbextentt)
89 			t = bbextentt;
90 		else if (t < 0)
91 			t = 0;
92 
93 		do
94 		{
95 		// calculate s and t at the far end of the span
96 			if (count >= 8)
97 				spancount = 8;
98 			else
99 				spancount = count;
100 
101 			count -= spancount;
102 
103 			if (count)
104 			{
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;
109 				zi += zi8stepu;
110 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
111 
112 				snext = (int)(sdivz * z) + sadjust;
113 				if (snext > bbextents)
114 					snext = bbextents;
115 				else if (snext < 8)
116 					snext = 8;	// prevent round-off error on <0 steps from
117 								//  from causing overstepping & running off the
118 								//  edge of the texture
119 
120 				tnext = (int)(tdivz * z) + tadjust;
121 				if (tnext > bbextentt)
122 					tnext = bbextentt;
123 				else if (tnext < 8)
124 					tnext = 8;	// guard against round-off error on <0 steps
125 
126 				sstep = (snext - s) >> 3;
127 				tstep = (tnext - t) >> 3;
128 			}
129 			else
130 			{
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
134 			// texture
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)
142 					snext = bbextents;
143 				else if (snext < 8)
144 					snext = 8;	// prevent round-off error on <0 steps from
145 								//  from causing overstepping & running off the
146 								//  edge of the texture
147 
148 				tnext = (int)(tdivz * z) + tadjust;
149 				if (tnext > bbextentt)
150 					tnext = bbextentt;
151 				else if (tnext < 8)
152 					tnext = 8;	// guard against round-off error on <0 steps
153 
154 				if (spancount > 1)
155 				{
156 					sstep = (snext - s) / (spancount - 1);
157 					tstep = (tnext - t) / (spancount - 1);
158 				}
159 			}
160 
161 			do
162 			{
163 				btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
164 				if (btemp != 255)
165 				{
166 					if (*pz <= (izi >> 16))
167 					{
168 						*pz = izi >> 16;
169 						*pdest = btemp;
170 					}
171 				}
172 
173 				izi += izistep;
174 				pdest++;
175 				pz++;
176 				s += sstep;
177 				t += tstep;
178 			} while (--spancount > 0);
179 
180 			s = snext;
181 			t = tnext;
182 
183 		} while (count > 0);
184 
185 NextSpan:
186 		pspan++;
187 
188 	} while (pspan->count != DS_SPAN_LIST_END);
189 }
190 
191 #endif
192 
193 
194 /*
195 =====================
196 D_SpriteScanLeftEdge
197 =====================
198 */
D_SpriteScanLeftEdge(void)199 void D_SpriteScanLeftEdge (void)
200 {
201 	int			i, v, itop, ibottom, lmaxindex;
202 	emitpoint_t	*pvert, *pnext;
203 	sspan_t		*pspan;
204 	float		du, dv, vtop, vbottom, slope;
205 	fixed16_t	u, u_step;
206 
207 	pspan = sprite_spans;
208 	i = minindex;
209 	if (i == 0)
210 		i = r_spritedesc.nump;
211 
212 	lmaxindex = maxindex;
213 	if (lmaxindex == 0)
214 		lmaxindex = r_spritedesc.nump;
215 
216 	vtop = ceil (r_spritedesc.pverts[i].v);
217 
218 	do
219 	{
220 		pvert = &r_spritedesc.pverts[i];
221 		pnext = pvert - 1;
222 
223 		vbottom = ceil (pnext->v);
224 
225 		if (vtop < vbottom)
226 		{
227 			du = pnext->u - pvert->u;
228 			dv = pnext->v - pvert->v;
229 			slope = du / dv;
230 			u_step = (int)(slope * 0x10000);
231 		// adjust u to ceil the integer portion
232 			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
233 					(0x10000 - 1);
234 			itop = (int)vtop;
235 			ibottom = (int)vbottom;
236 
237 			for (v=itop ; v<ibottom ; v++)
238 			{
239 				pspan->u = u >> 16;
240 				pspan->v = v;
241 				u += u_step;
242 				pspan++;
243 			}
244 		}
245 
246 		vtop = vbottom;
247 
248 		i--;
249 		if (i == 0)
250 			i = r_spritedesc.nump;
251 
252 	} while (i != lmaxindex);
253 }
254 
255 
256 /*
257 =====================
258 D_SpriteScanRightEdge
259 =====================
260 */
D_SpriteScanRightEdge(void)261 void D_SpriteScanRightEdge (void)
262 {
263 	int			i, v, itop, ibottom;
264 	emitpoint_t	*pvert, *pnext;
265 	sspan_t		*pspan;
266 	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
267 	fixed16_t	u, u_step;
268 
269 	pspan = sprite_spans;
270 	i = minindex;
271 
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;
277 
278 	vtop = ceil (vvert);
279 
280 	do
281 	{
282 		pvert = &r_spritedesc.pverts[i];
283 		pnext = pvert + 1;
284 
285 		vnext = pnext->v;
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;
290 
291 		vbottom = ceil (vnext);
292 
293 		if (vtop < vbottom)
294 		{
295 			uvert = pvert->u;
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;
300 
301 			unext = pnext->u;
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;
306 
307 			du = unext - uvert;
308 			dv = vnext - vvert;
309 			slope = du / dv;
310 			u_step = (int)(slope * 0x10000);
311 		// adjust u to ceil the integer portion
312 			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
313 					(0x10000 - 1);
314 			itop = (int)vtop;
315 			ibottom = (int)vbottom;
316 
317 			for (v=itop ; v<ibottom ; v++)
318 			{
319 				pspan->count = (u >> 16) - pspan->u;
320 				u += u_step;
321 				pspan++;
322 			}
323 		}
324 
325 		vtop = vbottom;
326 		vvert = vnext;
327 
328 		i++;
329 		if (i == r_spritedesc.nump)
330 			i = 0;
331 
332 	} while (i != maxindex);
333 
334 	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list
335 }
336 
337 
338 /*
339 =====================
340 D_SpriteCalculateGradients
341 =====================
342 */
D_SpriteCalculateGradients(void)343 void D_SpriteCalculateGradients (void)
344 {
345 	vec3_t		p_normal, p_saxis, p_taxis, p_temp1;
346 	float		distinv;
347 
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);
352 
353 	distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
354 
355 	d_sdivzstepu = p_saxis[0] * xscaleinv;
356 	d_tdivzstepu = p_taxis[0] * xscaleinv;
357 
358 	d_sdivzstepv = -p_saxis[1] * yscaleinv;
359 	d_tdivzstepv = -p_taxis[1] * yscaleinv;
360 
361 	d_zistepu = p_normal[0] * xscaleinv * distinv;
362 	d_zistepv = -p_normal[1] * yscaleinv * distinv;
363 
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 -
369 			ycenter * d_zistepv;
370 
371 	TransformVector (modelorg, p_temp1);
372 
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);
377 
378 // -1 (-epsilon) so we never wander off the edge of the texture
379 	bbextents = (cachewidth << 16) - 1;
380 	bbextentt = (sprite_height << 16) - 1;
381 }
382 
383 
384 /*
385 =====================
386 D_DrawSprite
387 =====================
388 */
D_DrawSprite(void)389 void D_DrawSprite (void)
390 {
391 	int			i, nump;
392 	float		ymin, ymax;
393 	emitpoint_t	*pverts;
394 	sspan_t		spans[MAXHEIGHT+1];
395 
396 	sprite_spans = spans;
397 
398 // find the top and bottom vertices, and make sure there's at least one scan to
399 // draw
400 	ymin = 999999.9;
401 	ymax = -999999.9;
402 	pverts = r_spritedesc.pverts;
403 
404 	for (i=0 ; i<r_spritedesc.nump ; i++)
405 	{
406 		if (pverts->v < ymin)
407 		{
408 			ymin = pverts->v;
409 			minindex = i;
410 		}
411 
412 		if (pverts->v > ymax)
413 		{
414 			ymax = pverts->v;
415 			maxindex = i;
416 		}
417 
418 		pverts++;
419 	}
420 
421 	ymin = ceil (ymin);
422 	ymax = ceil (ymax);
423 
424 	if (ymin >= ymax)
425 		return;		// doesn't cross any scans at all
426 
427 	cachewidth = r_spritedesc.pspriteframe->width;
428 	sprite_height = r_spritedesc.pspriteframe->height;
429 	cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
430 
431 // copy the first vertex to the last vertex, so we don't have to deal with
432 // wrapping
433 	nump = r_spritedesc.nump;
434 	pverts = r_spritedesc.pverts;
435 	pverts[nump] = pverts[0];
436 
437 	D_SpriteCalculateGradients ();
438 	D_SpriteScanLeftEdge ();
439 	D_SpriteScanRightEdge ();
440 	D_SpriteDrawSpans (sprite_spans);
441 }
442 
443