1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// d_polyset.c: routines for drawing sets of polygons sharing the same
21// texture (used for Alias models)
22
23#include "quakedef.h"
24#include "r_local.h"
25#include "d_local.h"
26
27// TODO: put in span spilling to shrink list size
28// !!! if this is changed, it must be changed in d_polysa.s too !!!
29#define DPS_MAXSPANS			MAXHEIGHT+1
30									// 1 extra for spanpackage that marks end
31
32// !!! if this is changed, it must be changed in asm_draw.h too !!!
33typedef struct {
34	void			*pdest;
35	short			*pz;
36	int				count;
37	byte			*ptex;
38	int				sfrac, tfrac, light, zi;
39} spanpackage_t;
40
41typedef struct {
42	int		isflattop;
43	int		numleftedges;
44	int		*pleftedgevert0;
45	int		*pleftedgevert1;
46	int		*pleftedgevert2;
47	int		numrightedges;
48	int		*prightedgevert0;
49	int		*prightedgevert1;
50	int		*prightedgevert2;
51} edgetable;
52
53int	r_p0[6], r_p1[6], r_p2[6];
54
55byte		*d_pcolormap;
56
57int			d_aflatcolor;
58int			d_xdenom;
59
60edgetable	*pedgetable;
61
62edgetable	edgetables[12] = {
63	{0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
64	{0, 2, r_p1, r_p0, r_p2,   1, r_p1, r_p2, NULL},
65	{1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
66	{0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
67	{0, 2, r_p0, r_p2, r_p1,   1, r_p0, r_p1, NULL},
68	{0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
69	{0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
70	{0, 2, r_p2, r_p1, r_p0,   1, r_p2, r_p0, NULL},
71	{0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
72	{1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
73	{1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
74	{0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
75};
76
77// FIXME: some of these can become statics
78int				a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
79int				r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
80int				r_zistepx, r_zistepy;
81int				d_aspancount, d_countextrastep;
82
83spanpackage_t			*a_spans;
84spanpackage_t			*d_pedgespanpackage;
85static int				ystart;
86byte					*d_pdest, *d_ptex;
87short					*d_pz;
88int						d_sfrac, d_tfrac, d_light, d_zi;
89int						d_ptexextrastep, d_sfracextrastep;
90int						d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
91int						d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
92int						d_sfracbasestep, d_tfracbasestep;
93int						d_ziextrastep, d_zibasestep;
94int						d_pzextrastep, d_pzbasestep;
95
96typedef struct {
97	int		quotient;
98	int		remainder;
99} adivtab_t;
100
101static adivtab_t	adivtab[32*32] = {
102#include "adivtab.h"
103};
104
105byte	*skintable[MAX_LBM_HEIGHT];
106int		skinwidth;
107byte	*skinstart;
108
109void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage);
110void D_PolysetCalcGradients (int skinwidth);
111void D_DrawSubdiv (void);
112void D_DrawNonSubdiv (void);
113void D_PolysetRecursiveTriangle (int *p1, int *p2, int *p3);
114void D_PolysetSetEdgeTable (void);
115void D_RasterizeAliasPolySmooth (void);
116void D_PolysetScanLeftEdge (int height);
117
118#if	!id386
119
120/*
121================
122D_PolysetDraw
123================
124*/
125void D_PolysetDraw (void)
126{
127	spanpackage_t	spans[DPS_MAXSPANS + 1 +
128			((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1];
129						// one extra because of cache line pretouching
130
131	a_spans = (spanpackage_t *)
132			(((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
133
134	if (r_affinetridesc.drawtype)
135	{
136		D_DrawSubdiv ();
137	}
138	else
139	{
140		D_DrawNonSubdiv ();
141	}
142}
143
144
145/*
146================
147D_PolysetDrawFinalVerts
148================
149*/
150void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts)
151{
152	int		i, z;
153	short	*zbuf;
154
155	for (i=0 ; i<numverts ; i++, fv++)
156	{
157	// valid triangle coordinates for filling can include the bottom and
158	// right clip edges, due to the fill rule; these shouldn't be drawn
159		if ((fv->v[0] < r_refdef.vrectright) &&
160			(fv->v[1] < r_refdef.vrectbottom))
161		{
162			z = fv->v[5]>>16;
163			zbuf = zspantable[fv->v[1]] + fv->v[0];
164			if (z >= *zbuf)
165			{
166				int		pix;
167
168				*zbuf = z;
169				pix = skintable[fv->v[3]>>16][fv->v[2]>>16];
170				pix = ((byte *)acolormap)[pix + (fv->v[4] & 0xFF00) ];
171				d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix;
172			}
173		}
174	}
175}
176
177
178/*
179================
180D_DrawSubdiv
181================
182*/
183void D_DrawSubdiv (void)
184{
185	mtriangle_t		*ptri;
186	finalvert_t		*pfv, *index0, *index1, *index2;
187	int				i;
188	int				lnumtriangles;
189
190	pfv = r_affinetridesc.pfinalverts;
191	ptri = r_affinetridesc.ptriangles;
192	lnumtriangles = r_affinetridesc.numtriangles;
193
194	for (i=0 ; i<lnumtriangles ; i++)
195	{
196		index0 = pfv + ptri[i].vertindex[0];
197		index1 = pfv + ptri[i].vertindex[1];
198		index2 = pfv + ptri[i].vertindex[2];
199
200		if (((index0->v[1]-index1->v[1]) *
201			 (index0->v[0]-index2->v[0]) -
202			 (index0->v[0]-index1->v[0]) *
203			 (index0->v[1]-index2->v[1])) >= 0)
204		{
205			continue;
206		}
207
208		d_pcolormap = &((byte *)acolormap)[index0->v[4] & 0xFF00];
209
210		if (ptri[i].facesfront)
211		{
212			D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v);
213		}
214		else
215		{
216			int		s0, s1, s2;
217
218			s0 = index0->v[2];
219			s1 = index1->v[2];
220			s2 = index2->v[2];
221
222			if (index0->flags & ALIAS_ONSEAM)
223				index0->v[2] += r_affinetridesc.seamfixupX16;
224			if (index1->flags & ALIAS_ONSEAM)
225				index1->v[2] += r_affinetridesc.seamfixupX16;
226			if (index2->flags & ALIAS_ONSEAM)
227				index2->v[2] += r_affinetridesc.seamfixupX16;
228
229			D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v);
230
231			index0->v[2] = s0;
232			index1->v[2] = s1;
233			index2->v[2] = s2;
234		}
235	}
236}
237
238
239/*
240================
241D_DrawNonSubdiv
242================
243*/
244void D_DrawNonSubdiv (void)
245{
246	mtriangle_t		*ptri;
247	finalvert_t		*pfv, *index0, *index1, *index2;
248	int				i;
249	int				lnumtriangles;
250
251	pfv = r_affinetridesc.pfinalverts;
252	ptri = r_affinetridesc.ptriangles;
253	lnumtriangles = r_affinetridesc.numtriangles;
254
255	for (i=0 ; i<lnumtriangles ; i++, ptri++)
256	{
257		index0 = pfv + ptri->vertindex[0];
258		index1 = pfv + ptri->vertindex[1];
259		index2 = pfv + ptri->vertindex[2];
260
261		d_xdenom = (index0->v[1]-index1->v[1]) *
262				(index0->v[0]-index2->v[0]) -
263				(index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]);
264
265		if (d_xdenom >= 0)
266		{
267			continue;
268		}
269
270		r_p0[0] = index0->v[0];		// u
271		r_p0[1] = index0->v[1];		// v
272		r_p0[2] = index0->v[2];		// s
273		r_p0[3] = index0->v[3];		// t
274		r_p0[4] = index0->v[4];		// light
275		r_p0[5] = index0->v[5];		// iz
276
277		r_p1[0] = index1->v[0];
278		r_p1[1] = index1->v[1];
279		r_p1[2] = index1->v[2];
280		r_p1[3] = index1->v[3];
281		r_p1[4] = index1->v[4];
282		r_p1[5] = index1->v[5];
283
284		r_p2[0] = index2->v[0];
285		r_p2[1] = index2->v[1];
286		r_p2[2] = index2->v[2];
287		r_p2[3] = index2->v[3];
288		r_p2[4] = index2->v[4];
289		r_p2[5] = index2->v[5];
290
291		if (!ptri->facesfront)
292		{
293			if (index0->flags & ALIAS_ONSEAM)
294				r_p0[2] += r_affinetridesc.seamfixupX16;
295			if (index1->flags & ALIAS_ONSEAM)
296				r_p1[2] += r_affinetridesc.seamfixupX16;
297			if (index2->flags & ALIAS_ONSEAM)
298				r_p2[2] += r_affinetridesc.seamfixupX16;
299		}
300
301		D_PolysetSetEdgeTable ();
302		D_RasterizeAliasPolySmooth ();
303	}
304}
305
306
307/*
308================
309D_PolysetRecursiveTriangle
310================
311*/
312void D_PolysetRecursiveTriangle (int *lp1, int *lp2, int *lp3)
313{
314	int		*temp;
315	int		d;
316	int		new[6];
317	int		z;
318	short	*zbuf;
319
320	d = lp2[0] - lp1[0];
321	if (d < -1 || d > 1)
322		goto split;
323	d = lp2[1] - lp1[1];
324	if (d < -1 || d > 1)
325		goto split;
326
327	d = lp3[0] - lp2[0];
328	if (d < -1 || d > 1)
329		goto split2;
330	d = lp3[1] - lp2[1];
331	if (d < -1 || d > 1)
332		goto split2;
333
334	d = lp1[0] - lp3[0];
335	if (d < -1 || d > 1)
336		goto split3;
337	d = lp1[1] - lp3[1];
338	if (d < -1 || d > 1)
339	{
340split3:
341		temp = lp1;
342		lp1 = lp3;
343		lp3 = lp2;
344		lp2 = temp;
345
346		goto split;
347	}
348
349	return;			// entire tri is filled
350
351split2:
352	temp = lp1;
353	lp1 = lp2;
354	lp2 = lp3;
355	lp3 = temp;
356
357split:
358// split this edge
359	new[0] = (lp1[0] + lp2[0]) >> 1;
360	new[1] = (lp1[1] + lp2[1]) >> 1;
361	new[2] = (lp1[2] + lp2[2]) >> 1;
362	new[3] = (lp1[3] + lp2[3]) >> 1;
363	new[5] = (lp1[5] + lp2[5]) >> 1;
364
365// draw the point if splitting a leading edge
366	if (lp2[1] > lp1[1])
367		goto nodraw;
368	if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0]))
369		goto nodraw;
370
371
372	z = new[5]>>16;
373	zbuf = zspantable[new[1]] + new[0];
374	if (z >= *zbuf)
375	{
376		int		pix;
377
378		*zbuf = z;
379		pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]];
380		d_viewbuffer[d_scantable[new[1]] + new[0]] = pix;
381	}
382
383nodraw:
384// recursively continue
385	D_PolysetRecursiveTriangle (lp3, lp1, new);
386	D_PolysetRecursiveTriangle (lp3, new, lp2);
387}
388
389#endif	// !id386
390
391
392/*
393================
394D_PolysetUpdateTables
395================
396*/
397void D_PolysetUpdateTables (void)
398{
399	int		i;
400	byte	*s;
401
402	if (r_affinetridesc.skinwidth != skinwidth ||
403		r_affinetridesc.pskin != skinstart)
404	{
405		skinwidth = r_affinetridesc.skinwidth;
406		skinstart = r_affinetridesc.pskin;
407		s = skinstart;
408		for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
409			skintable[i] = s;
410	}
411}
412
413
414#if	!id386
415
416/*
417===================
418D_PolysetScanLeftEdge
419====================
420*/
421void D_PolysetScanLeftEdge (int height)
422{
423
424	do
425	{
426		d_pedgespanpackage->pdest = d_pdest;
427		d_pedgespanpackage->pz = d_pz;
428		d_pedgespanpackage->count = d_aspancount;
429		d_pedgespanpackage->ptex = d_ptex;
430
431		d_pedgespanpackage->sfrac = d_sfrac;
432		d_pedgespanpackage->tfrac = d_tfrac;
433
434	// FIXME: need to clamp l, s, t, at both ends?
435		d_pedgespanpackage->light = d_light;
436		d_pedgespanpackage->zi = d_zi;
437
438		d_pedgespanpackage++;
439
440		errorterm += erroradjustup;
441		if (errorterm >= 0)
442		{
443			d_pdest += d_pdestextrastep;
444			d_pz += d_pzextrastep;
445			d_aspancount += d_countextrastep;
446			d_ptex += d_ptexextrastep;
447			d_sfrac += d_sfracextrastep;
448			d_ptex += d_sfrac >> 16;
449
450			d_sfrac &= 0xFFFF;
451			d_tfrac += d_tfracextrastep;
452			if (d_tfrac & 0x10000)
453			{
454				d_ptex += r_affinetridesc.skinwidth;
455				d_tfrac &= 0xFFFF;
456			}
457			d_light += d_lightextrastep;
458			d_zi += d_ziextrastep;
459			errorterm -= erroradjustdown;
460		}
461		else
462		{
463			d_pdest += d_pdestbasestep;
464			d_pz += d_pzbasestep;
465			d_aspancount += ubasestep;
466			d_ptex += d_ptexbasestep;
467			d_sfrac += d_sfracbasestep;
468			d_ptex += d_sfrac >> 16;
469			d_sfrac &= 0xFFFF;
470			d_tfrac += d_tfracbasestep;
471			if (d_tfrac & 0x10000)
472			{
473				d_ptex += r_affinetridesc.skinwidth;
474				d_tfrac &= 0xFFFF;
475			}
476			d_light += d_lightbasestep;
477			d_zi += d_zibasestep;
478		}
479	} while (--height);
480}
481
482#endif	// !id386
483
484
485/*
486===================
487D_PolysetSetUpForLineScan
488====================
489*/
490void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
491		fixed8_t endvertu, fixed8_t endvertv)
492{
493	double		dm, dn;
494	int			tm, tn;
495	adivtab_t	*ptemp;
496
497// TODO: implement x86 version
498
499	errorterm = -1;
500
501	tm = endvertu - startvertu;
502	tn = endvertv - startvertv;
503
504	if (((tm <= 16) && (tm >= -15)) &&
505		((tn <= 16) && (tn >= -15)))
506	{
507		ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
508		ubasestep = ptemp->quotient;
509		erroradjustup = ptemp->remainder;
510		erroradjustdown = tn;
511	}
512	else
513	{
514		dm = (double)tm;
515		dn = (double)tn;
516
517		FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
518
519		erroradjustdown = dn;
520	}
521}
522
523
524#if	!id386
525
526/*
527================
528D_PolysetCalcGradients
529================
530*/
531void D_PolysetCalcGradients (int skinwidth)
532{
533	float	xstepdenominv, ystepdenominv, t0, t1;
534	float	p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
535
536	p00_minus_p20 = r_p0[0] - r_p2[0];
537	p01_minus_p21 = r_p0[1] - r_p2[1];
538	p10_minus_p20 = r_p1[0] - r_p2[0];
539	p11_minus_p21 = r_p1[1] - r_p2[1];
540
541	xstepdenominv = 1.0 / (float)d_xdenom;
542
543	ystepdenominv = -xstepdenominv;
544
545// ceil () for light so positive steps are exaggerated, negative steps
546// diminished,  pushing us away from underflow toward overflow. Underflow is
547// very visible, overflow is very unlikely, because of ambient lighting
548	t0 = r_p0[4] - r_p2[4];
549	t1 = r_p1[4] - r_p2[4];
550	r_lstepx = (int)
551			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
552	r_lstepy = (int)
553			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
554
555	t0 = r_p0[2] - r_p2[2];
556	t1 = r_p1[2] - r_p2[2];
557	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
558			xstepdenominv);
559	r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
560			ystepdenominv);
561
562	t0 = r_p0[3] - r_p2[3];
563	t1 = r_p1[3] - r_p2[3];
564	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
565			xstepdenominv);
566	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
567			ystepdenominv);
568
569	t0 = r_p0[5] - r_p2[5];
570	t1 = r_p1[5] - r_p2[5];
571	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
572			xstepdenominv);
573	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
574			ystepdenominv);
575
576#if	id386
577	a_sstepxfrac = r_sstepx << 16;
578	a_tstepxfrac = r_tstepx << 16;
579#else
580	a_sstepxfrac = r_sstepx & 0xFFFF;
581	a_tstepxfrac = r_tstepx & 0xFFFF;
582#endif
583
584	a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
585}
586
587#endif	// !id386
588
589
590#if 0
591byte gelmap[256];
592void InitGel (byte *palette)
593{
594	int		i;
595	int		r;
596
597	for (i=0 ; i<256 ; i++)
598	{
599//		r = (palette[i*3]>>4);
600		r = (palette[i*3] + palette[i*3+1] + palette[i*3+2])/(16*3);
601		gelmap[i] = /* 64 */ 0 + r;
602	}
603}
604#endif
605
606
607#if	!id386
608
609/*
610================
611D_PolysetDrawSpans8
612================
613*/
614void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage)
615{
616	int		lcount;
617	byte	*lpdest;
618	byte	*lptex;
619	int		lsfrac, ltfrac;
620	int		llight;
621	int		lzi;
622	short	*lpz;
623
624	do
625	{
626		lcount = d_aspancount - pspanpackage->count;
627
628		errorterm += erroradjustup;
629		if (errorterm >= 0)
630		{
631			d_aspancount += d_countextrastep;
632			errorterm -= erroradjustdown;
633		}
634		else
635		{
636			d_aspancount += ubasestep;
637		}
638
639		if (lcount)
640		{
641			lpdest = pspanpackage->pdest;
642			lptex = pspanpackage->ptex;
643			lpz = pspanpackage->pz;
644			lsfrac = pspanpackage->sfrac;
645			ltfrac = pspanpackage->tfrac;
646			llight = pspanpackage->light;
647			lzi = pspanpackage->zi;
648
649			do
650			{
651				if ((lzi >> 16) >= *lpz)
652				{
653					*lpdest = ((byte *)acolormap)[*lptex + (llight & 0xFF00)];
654// gel mapping					*lpdest = gelmap[*lpdest];
655					*lpz = lzi >> 16;
656				}
657				lpdest++;
658				lzi += r_zistepx;
659				lpz++;
660				llight += r_lstepx;
661				lptex += a_ststepxwhole;
662				lsfrac += a_sstepxfrac;
663				lptex += lsfrac >> 16;
664				lsfrac &= 0xFFFF;
665				ltfrac += a_tstepxfrac;
666				if (ltfrac & 0x10000)
667				{
668					lptex += r_affinetridesc.skinwidth;
669					ltfrac &= 0xFFFF;
670				}
671			} while (--lcount);
672		}
673
674		pspanpackage++;
675	} while (pspanpackage->count != -999999);
676}
677#endif	// !id386
678
679
680/*
681================
682D_PolysetFillSpans8
683================
684*/
685void D_PolysetFillSpans8 (spanpackage_t *pspanpackage)
686{
687	int				color;
688
689// FIXME: do z buffering
690
691	color = d_aflatcolor++;
692
693	while (1)
694	{
695		int		lcount;
696		byte	*lpdest;
697
698		lcount = pspanpackage->count;
699
700		if (lcount == -1)
701			return;
702
703		if (lcount)
704		{
705			lpdest = pspanpackage->pdest;
706
707			do
708			{
709				*lpdest++ = color;
710			} while (--lcount);
711		}
712
713		pspanpackage++;
714	}
715}
716
717/*
718================
719D_RasterizeAliasPolySmooth
720================
721*/
722void D_RasterizeAliasPolySmooth (void)
723{
724	int				initialleftheight, initialrightheight;
725	int				*plefttop, *prighttop, *pleftbottom, *prightbottom;
726	int				working_lstepx, originalcount;
727
728	plefttop = pedgetable->pleftedgevert0;
729	prighttop = pedgetable->prightedgevert0;
730
731	pleftbottom = pedgetable->pleftedgevert1;
732	prightbottom = pedgetable->prightedgevert1;
733
734	initialleftheight = pleftbottom[1] - plefttop[1];
735	initialrightheight = prightbottom[1] - prighttop[1];
736
737//
738// set the s, t, and light gradients, which are consistent across the triangle
739// because being a triangle, things are affine
740//
741	D_PolysetCalcGradients (r_affinetridesc.skinwidth);
742
743//
744// rasterize the polygon
745//
746
747//
748// scan out the top (and possibly only) part of the left edge
749//
750	d_pedgespanpackage = a_spans;
751
752	ystart = plefttop[1];
753	d_aspancount = plefttop[0] - prighttop[0];
754
755	d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
756			(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
757#if	id386
758	d_sfrac = (plefttop[2] & 0xFFFF) << 16;
759	d_tfrac = (plefttop[3] & 0xFFFF) << 16;
760#else
761	d_sfrac = plefttop[2] & 0xFFFF;
762	d_tfrac = plefttop[3] & 0xFFFF;
763#endif
764	d_light = plefttop[4];
765	d_zi = plefttop[5];
766
767	d_pdest = (byte *)d_viewbuffer +
768			ystart * screenwidth + plefttop[0];
769	d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
770
771	if (initialleftheight == 1)
772	{
773		d_pedgespanpackage->pdest = d_pdest;
774		d_pedgespanpackage->pz = d_pz;
775		d_pedgespanpackage->count = d_aspancount;
776		d_pedgespanpackage->ptex = d_ptex;
777
778		d_pedgespanpackage->sfrac = d_sfrac;
779		d_pedgespanpackage->tfrac = d_tfrac;
780
781	// FIXME: need to clamp l, s, t, at both ends?
782		d_pedgespanpackage->light = d_light;
783		d_pedgespanpackage->zi = d_zi;
784
785		d_pedgespanpackage++;
786	}
787	else
788	{
789		D_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
790							  pleftbottom[0], pleftbottom[1]);
791
792	#if	id386
793		d_pzbasestep = (d_zwidth + ubasestep) << 1;
794		d_pzextrastep = d_pzbasestep + 2;
795	#else
796		d_pzbasestep = d_zwidth + ubasestep;
797		d_pzextrastep = d_pzbasestep + 1;
798	#endif
799
800		d_pdestbasestep = screenwidth + ubasestep;
801		d_pdestextrastep = d_pdestbasestep + 1;
802
803	// TODO: can reuse partial expressions here
804
805	// for negative steps in x along left edge, bias toward overflow rather than
806	// underflow (sort of turning the floor () we did in the gradient calcs into
807	// ceil (), but plus a little bit)
808		if (ubasestep < 0)
809			working_lstepx = r_lstepx - 1;
810		else
811			working_lstepx = r_lstepx;
812
813		d_countextrastep = ubasestep + 1;
814		d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
815				((r_tstepy + r_tstepx * ubasestep) >> 16) *
816				r_affinetridesc.skinwidth;
817	#if	id386
818		d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
819		d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
820	#else
821		d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
822		d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
823	#endif
824		d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
825		d_zibasestep = r_zistepy + r_zistepx * ubasestep;
826
827		d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
828				((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
829				r_affinetridesc.skinwidth;
830	#if	id386
831		d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16;
832		d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16;
833	#else
834		d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
835		d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
836	#endif
837		d_lightextrastep = d_lightbasestep + working_lstepx;
838		d_ziextrastep = d_zibasestep + r_zistepx;
839
840		D_PolysetScanLeftEdge (initialleftheight);
841	}
842
843//
844// scan out the bottom part of the left edge, if it exists
845//
846	if (pedgetable->numleftedges == 2)
847	{
848		int		height;
849
850		plefttop = pleftbottom;
851		pleftbottom = pedgetable->pleftedgevert2;
852
853		height = pleftbottom[1] - plefttop[1];
854
855// TODO: make this a function; modularize this function in general
856
857		ystart = plefttop[1];
858		d_aspancount = plefttop[0] - prighttop[0];
859		d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
860				(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
861		d_sfrac = 0;
862		d_tfrac = 0;
863		d_light = plefttop[4];
864		d_zi = plefttop[5];
865
866		d_pdest = (byte *)d_viewbuffer + ystart * screenwidth + plefttop[0];
867		d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
868
869		if (height == 1)
870		{
871			d_pedgespanpackage->pdest = d_pdest;
872			d_pedgespanpackage->pz = d_pz;
873			d_pedgespanpackage->count = d_aspancount;
874			d_pedgespanpackage->ptex = d_ptex;
875
876			d_pedgespanpackage->sfrac = d_sfrac;
877			d_pedgespanpackage->tfrac = d_tfrac;
878
879		// FIXME: need to clamp l, s, t, at both ends?
880			d_pedgespanpackage->light = d_light;
881			d_pedgespanpackage->zi = d_zi;
882
883			d_pedgespanpackage++;
884		}
885		else
886		{
887			D_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
888								  pleftbottom[0], pleftbottom[1]);
889
890			d_pdestbasestep = screenwidth + ubasestep;
891			d_pdestextrastep = d_pdestbasestep + 1;
892
893	#if	id386
894			d_pzbasestep = (d_zwidth + ubasestep) << 1;
895			d_pzextrastep = d_pzbasestep + 2;
896	#else
897			d_pzbasestep = d_zwidth + ubasestep;
898			d_pzextrastep = d_pzbasestep + 1;
899	#endif
900
901			if (ubasestep < 0)
902				working_lstepx = r_lstepx - 1;
903			else
904				working_lstepx = r_lstepx;
905
906			d_countextrastep = ubasestep + 1;
907			d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
908					((r_tstepy + r_tstepx * ubasestep) >> 16) *
909					r_affinetridesc.skinwidth;
910	#if	id386
911			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
912			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
913	#else
914			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
915			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
916	#endif
917			d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
918			d_zibasestep = r_zistepy + r_zistepx * ubasestep;
919
920			d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
921					((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
922					r_affinetridesc.skinwidth;
923	#if	id386
924			d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16;
925			d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16;
926	#else
927			d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
928			d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
929	#endif
930			d_lightextrastep = d_lightbasestep + working_lstepx;
931			d_ziextrastep = d_zibasestep + r_zistepx;
932
933			D_PolysetScanLeftEdge (height);
934		}
935	}
936
937// scan out the top (and possibly only) part of the right edge, updating the
938// count field
939	d_pedgespanpackage = a_spans;
940
941	D_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
942						  prightbottom[0], prightbottom[1]);
943	d_aspancount = 0;
944	d_countextrastep = ubasestep + 1;
945	originalcount = a_spans[initialrightheight].count;
946	a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
947	D_PolysetDrawSpans8 (a_spans);
948
949// scan out the bottom part of the right edge, if it exists
950	if (pedgetable->numrightedges == 2)
951	{
952		int				height;
953		spanpackage_t	*pstart;
954
955		pstart = a_spans + initialrightheight;
956		pstart->count = originalcount;
957
958		d_aspancount = prightbottom[0] - prighttop[0];
959
960		prighttop = prightbottom;
961		prightbottom = pedgetable->prightedgevert2;
962
963		height = prightbottom[1] - prighttop[1];
964
965		D_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
966							  prightbottom[0], prightbottom[1]);
967
968		d_countextrastep = ubasestep + 1;
969		a_spans[initialrightheight + height].count = -999999;
970											// mark end of the spanpackages
971		D_PolysetDrawSpans8 (pstart);
972	}
973}
974
975
976/*
977================
978D_PolysetSetEdgeTable
979================
980*/
981void D_PolysetSetEdgeTable (void)
982{
983	int			edgetableindex;
984
985	edgetableindex = 0;	// assume the vertices are already in
986						//  top to bottom order
987
988//
989// determine which edges are right & left, and the order in which
990// to rasterize them
991//
992	if (r_p0[1] >= r_p1[1])
993	{
994		if (r_p0[1] == r_p1[1])
995		{
996			if (r_p0[1] < r_p2[1])
997				pedgetable = &edgetables[2];
998			else
999				pedgetable = &edgetables[5];
1000
1001			return;
1002		}
1003		else
1004		{
1005			edgetableindex = 1;
1006		}
1007	}
1008
1009	if (r_p0[1] == r_p2[1])
1010	{
1011		if (edgetableindex)
1012			pedgetable = &edgetables[8];
1013		else
1014			pedgetable = &edgetables[9];
1015
1016		return;
1017	}
1018	else if (r_p1[1] == r_p2[1])
1019	{
1020		if (edgetableindex)
1021			pedgetable = &edgetables[10];
1022		else
1023			pedgetable = &edgetables[11];
1024
1025		return;
1026	}
1027
1028	if (r_p0[1] > r_p2[1])
1029		edgetableindex += 2;
1030
1031	if (r_p1[1] > r_p2[1])
1032		edgetableindex += 4;
1033
1034	pedgetable = &edgetables[edgetableindex];
1035}
1036
1037
1038#if 0
1039
1040void D_PolysetRecursiveDrawLine (int *lp1, int *lp2)
1041{
1042	int		d;
1043	int		new[6];
1044	int 	ofs;
1045
1046	d = lp2[0] - lp1[0];
1047	if (d < -1 || d > 1)
1048		goto split;
1049	d = lp2[1] - lp1[1];
1050	if (d < -1 || d > 1)
1051		goto split;
1052
1053	return;	// line is completed
1054
1055split:
1056// split this edge
1057	new[0] = (lp1[0] + lp2[0]) >> 1;
1058	new[1] = (lp1[1] + lp2[1]) >> 1;
1059	new[5] = (lp1[5] + lp2[5]) >> 1;
1060	new[2] = (lp1[2] + lp2[2]) >> 1;
1061	new[3] = (lp1[3] + lp2[3]) >> 1;
1062	new[4] = (lp1[4] + lp2[4]) >> 1;
1063
1064// draw the point
1065	ofs = d_scantable[new[1]] + new[0];
1066	if (new[5] > d_pzbuffer[ofs])
1067	{
1068		int		pix;
1069
1070		d_pzbuffer[ofs] = new[5];
1071		pix = skintable[new[3]>>16][new[2]>>16];
1072//		pix = ((byte *)acolormap)[pix + (new[4] & 0xFF00)];
1073		d_viewbuffer[ofs] = pix;
1074	}
1075
1076// recursively continue
1077	D_PolysetRecursiveDrawLine (lp1, new);
1078	D_PolysetRecursiveDrawLine (new, lp2);
1079}
1080
1081void D_PolysetRecursiveTriangle2 (int *lp1, int *lp2, int *lp3)
1082{
1083	int		d;
1084	int		new[4];
1085
1086	d = lp2[0] - lp1[0];
1087	if (d < -1 || d > 1)
1088		goto split;
1089	d = lp2[1] - lp1[1];
1090	if (d < -1 || d > 1)
1091		goto split;
1092	return;
1093
1094split:
1095// split this edge
1096	new[0] = (lp1[0] + lp2[0]) >> 1;
1097	new[1] = (lp1[1] + lp2[1]) >> 1;
1098	new[5] = (lp1[5] + lp2[5]) >> 1;
1099	new[2] = (lp1[2] + lp2[2]) >> 1;
1100	new[3] = (lp1[3] + lp2[3]) >> 1;
1101	new[4] = (lp1[4] + lp2[4]) >> 1;
1102
1103	D_PolysetRecursiveDrawLine (new, lp3);
1104
1105// recursively continue
1106	D_PolysetRecursiveTriangle (lp1, new, lp3);
1107	D_PolysetRecursiveTriangle (new, lp2, lp3);
1108}
1109
1110#endif
1111
1112