Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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
*/
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
*/
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
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
*/
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
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
*/
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
*/
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
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