/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/
//
// d_spr8.s
// x86 assembly-language horizontal 8-bpp transparent span-drawing code.
//

#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"

//----------------------------------------------------------------------
// 8-bpp horizontal span drawing code for polygons, with transparency.
//----------------------------------------------------------------------

	.text

// out-of-line, rarely-needed clamping code

LClampHigh0:
	movl	C(bbextents),%esi
	jmp		LClampReentry0
LClampHighOrLow0:
	jg		LClampHigh0
	xorl	%esi,%esi
	jmp		LClampReentry0

LClampHigh1:
	movl	C(bbextentt),%edx
	jmp		LClampReentry1
LClampHighOrLow1:
	jg		LClampHigh1
	xorl	%edx,%edx
	jmp		LClampReentry1

LClampLow2:
	movl	$2048,%ebp
	jmp		LClampReentry2
LClampHigh2:
	movl	C(bbextents),%ebp
	jmp		LClampReentry2

LClampLow3:
	movl	$2048,%ecx
	jmp		LClampReentry3
LClampHigh3:
	movl	C(bbextentt),%ecx
	jmp		LClampReentry3

LClampLow4:
	movl	$2048,%eax
	jmp		LClampReentry4
LClampHigh4:
	movl	C(bbextents),%eax
	jmp		LClampReentry4

LClampLow5:
	movl	$2048,%ebx
	jmp		LClampReentry5
LClampHigh5:
	movl	C(bbextentt),%ebx
	jmp		LClampReentry5


#define pspans	4+16

	.align 4
.globl C(D_SpriteDrawSpans)
C(D_SpriteDrawSpans):
	pushl	%ebp				// preserve caller's stack frame
	pushl	%edi
	pushl	%esi				// preserve register variables
	pushl	%ebx

//
// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock
// and span list pointers, and 1/z step in 0.32 fixed-point
//
// FIXME: any overlap from rearranging?
	flds	C(d_sdivzstepu)
	fmuls	fp_8
	movl	C(cacheblock),%edx
	flds	C(d_tdivzstepu)
	fmuls	fp_8
	movl	pspans(%esp),%ebx	// point to the first span descriptor
	flds	C(d_zistepu)
	fmuls	fp_8
	movl	%edx,pbase			// pbase = cacheblock
	flds	C(d_zistepu)
	fmuls	fp_64kx64k
	fxch	%st(3)
	fstps	sdivz8stepu
	fstps	zi8stepu
	fstps	tdivz8stepu
	fistpl	izistep
	movl	izistep,%eax
	rorl	$16,%eax		// put upper 16 bits in low word
    movl    sspan_t_v(%ebx),%ecx
	cmpl	$0,%ecx
	jl		LNextSpan

	movl	sspan_t_count(%ebx),%ecx
	movl	%eax,izistep

	cmpl	$0,%ecx
	jle		LNextSpan

LSpanLoop:

//
// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
// initial s and t values
//
// FIXME: pipeline FILD?
	fildl	sspan_t_v(%ebx)
	fildl	sspan_t_u(%ebx)

	fld		%st(1)			// dv | du | dv
	fmuls	C(d_sdivzstepv)	// dv*d_sdivzstepv | du | dv
	fld		%st(1)			// du | dv*d_sdivzstepv | du | dv
	fmuls	C(d_sdivzstepu)	// du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
	fld		%st(2)			// du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
	fmuls	C(d_tdivzstepu)	// du*d_tdivzstepu | du*d_sdivzstepu |
							//  dv*d_sdivzstepv | du | dv
	fxch	%st(1)			// du*d_sdivzstepu | du*d_tdivzstepu |
							//  dv*d_sdivzstepv | du | dv
	faddp	%st(0),%st(2)	// du*d_tdivzstepu |
							//  du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
							//  du*d_tdivzstepu | du | dv
	fld		%st(3)			// dv | du*d_sdivzstepu + dv*d_sdivzstepv |
							//  du*d_tdivzstepu | du | dv
	fmuls	C(d_tdivzstepv)	// dv*d_tdivzstepv |
							//  du*d_sdivzstepu + dv*d_sdivzstepv |
							//  du*d_tdivzstepu | du | dv
	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
							//  dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
	fadds	C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv +
							//  du*d_sdivzstepu; stays in %st(2) at end
	fxch	%st(4)			// dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
							//  s/z
	fmuls	C(d_zistepv)		// dv*d_zistepv | dv*d_tdivzstepv |
							//  du*d_tdivzstepu | du | s/z
	fxch	%st(1)			// dv*d_tdivzstepv |  dv*d_zistepv |
							//  du*d_tdivzstepu | du | s/z
	faddp	%st(0),%st(2)	// dv*d_zistepv |
							//  dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
	fxch	%st(2)			// du | dv*d_tdivzstepv + du*d_tdivzstepu |
							//  dv*d_zistepv | s/z
	fmuls	C(d_zistepu)		// du*d_zistepu |
							//  dv*d_tdivzstepv + du*d_tdivzstepu |
							//  dv*d_zistepv | s/z
	fxch	%st(1)			// dv*d_tdivzstepv + du*d_tdivzstepu |
							//  du*d_zistepu | dv*d_zistepv | s/z
	fadds	C(d_tdivzorigin)	// tdivz = d_tdivzorigin + dv*d_tdivzstepv +
							//  du*d_tdivzstepu; stays in %st(1) at end
	fxch	%st(2)			// dv*d_zistepv | du*d_zistepu | t/z | s/z
	faddp	%st(0),%st(1)	// dv*d_zistepv + du*d_zistepu | t/z | s/z

	flds	fp_64k			// fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
	fxch	%st(1)			// dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
	fadds	C(d_ziorigin)		// zi = d_ziorigin + dv*d_zistepv +
							//  du*d_zistepu; stays in %st(0) at end
							// 1/z | fp_64k | t/z | s/z

	fld		%st(0)			// FIXME: get rid of stall on FMUL?
	fmuls	fp_64kx64k
	fxch	%st(1)

//
// calculate and clamp s & t
//
	fdivr	%st(0),%st(2)	// 1/z | z*64k | t/z | s/z
	fxch	%st(1)

	fistpl	izi				// 0.32 fixed-point 1/z
	movl	izi,%ebp

//
// set pz to point to the first z-buffer pixel in the span
//
	rorl	$16,%ebp		// put upper 16 bits in low word
	movl	sspan_t_v(%ebx),%eax
	movl	%ebp,izi
	movl	sspan_t_u(%ebx),%ebp
	imull	C(d_zrowbytes)
	shll	$1,%ebp					// a word per pixel
	addl	C(d_pzbuffer),%eax
	addl	%ebp,%eax
	movl	%eax,pz

//
// point %edi to the first pixel in the span
//
	movl	C(d_viewbuffer),%ebp
	movl	sspan_t_v(%ebx),%eax
	pushl	%ebx		// preserve spans pointer
	movl	C(tadjust),%edx
	movl	C(sadjust),%esi
	movl	C(d_scantable)(,%eax,4),%edi	// v * screenwidth
	addl	%ebp,%edi
	movl	sspan_t_u(%ebx),%ebp
	addl	%ebp,%edi				// pdest = &pdestspan[scans->u];

//
// now start the FDIV for the end of the span
//
	cmpl	$8,%ecx
	ja		LSetupNotLast1

	decl	%ecx
	jz		LCleanup1		// if only one pixel, no need to start an FDIV
	movl	%ecx,spancountminus1

// finish up the s and t calcs
	fxch	%st(1)			// z*64k | 1/z | t/z | s/z

	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
	fxch	%st(1)			// s | t | 1/z | t/z | s/z
	fistpl	s				// 1/z | t | t/z | s/z
	fistpl	t				// 1/z | t/z | s/z

	fildl	spancountminus1

	flds	C(d_tdivzstepu)	// _d_tdivzstepu | spancountminus1
	flds	C(d_zistepu)	// _d_zistepu | _d_tdivzstepu | spancountminus1
	fmul	%st(2),%st(0)	// _d_zistepu*scm1 | _d_tdivzstepu | scm1
	fxch	%st(1)			// _d_tdivzstepu | _d_zistepu*scm1 | scm1
	fmul	%st(2),%st(0)	// _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
	fxch	%st(2)			// scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1
	fmuls	C(d_sdivzstepu)	// _d_sdivzstepu*scm1 | _d_zistepu*scm1 |
							//  _d_tdivzstepu*scm1
	fxch	%st(1)			// _d_zistepu*scm1 | _d_sdivzstepu*scm1 |
							//  _d_tdivzstepu*scm1
	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
	fxch	%st(1)			// _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1
	faddp	%st(0),%st(3)

	flds	fp_64k
	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
							//  overlap
	jmp		LFDIVInFlight1

LCleanup1:
// finish up the s and t calcs
	fxch	%st(1)			// z*64k | 1/z | t/z | s/z

	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
	fxch	%st(1)			// s | t | 1/z | t/z | s/z
	fistpl	s				// 1/z | t | t/z | s/z
	fistpl	t				// 1/z | t/z | s/z
	jmp		LFDIVInFlight1

	.align	4
LSetupNotLast1:
// finish up the s and t calcs
	fxch	%st(1)			// z*64k | 1/z | t/z | s/z

	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
	fxch	%st(1)			// s | t | 1/z | t/z | s/z
	fistpl	s				// 1/z | t | t/z | s/z
	fistpl	t				// 1/z | t/z | s/z

	fadds	zi8stepu
	fxch	%st(2)
	fadds	sdivz8stepu
	fxch	%st(2)
	flds	tdivz8stepu
	faddp	%st(0),%st(2)
	flds	fp_64k
	fdiv	%st(1),%st(0)	// z = 1/1/z
							// this is what we've gone to all this trouble to
							//  overlap
LFDIVInFlight1:

	addl	s,%esi
	addl	t,%edx
	movl	C(bbextents),%ebx
	movl	C(bbextentt),%ebp
	cmpl	%ebx,%esi
	ja		LClampHighOrLow0
LClampReentry0:
	movl	%esi,s
	movl	pbase,%ebx
	shll	$16,%esi
	cmpl	%ebp,%edx
	movl	%esi,sfracf
	ja		LClampHighOrLow1
LClampReentry1:
	movl	%edx,t
	movl	s,%esi					// sfrac = scans->sfrac;
	shll	$16,%edx
	movl	t,%eax					// tfrac = scans->tfrac;
	sarl	$16,%esi
	movl	%edx,tfracf

//
// calculate the texture starting address
//
	sarl	$16,%eax
	addl	%ebx,%esi
	imull	C(cachewidth),%eax		// (tfrac >> 16) * cachewidth
	addl	%eax,%esi				// psource = pbase + (sfrac >> 16) +
									//           ((tfrac >> 16) * cachewidth);

//
// determine whether last span or not
//
	cmpl	$8,%ecx
	jna		LLastSegment

//
// not the last segment; do full 8-wide segment
//
LNotLastSegment:

//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there
//

// pick up after the FDIV that was left in flight previously

	fld		%st(0)			// duplicate it
	fmul	%st(4),%st(0)	// s = s/z * z
	fxch	%st(1)
	fmul	%st(3),%st(0)	// t = t/z * z
	fxch	%st(1)
	fistpl	snext
	fistpl	tnext
	movl	snext,%eax
	movl	tnext,%edx

	subl	$8,%ecx		// count off this segments' pixels
	movl	C(sadjust),%ebp
	pushl	%ecx		// remember count of remaining pixels
	movl	C(tadjust),%ecx

	addl	%eax,%ebp
	addl	%edx,%ecx

	movl	C(bbextents),%eax
	movl	C(bbextentt),%edx

	cmpl	$2048,%ebp
	jl		LClampLow2
	cmpl	%eax,%ebp
	ja		LClampHigh2
LClampReentry2:

	cmpl	$2048,%ecx
	jl		LClampLow3
	cmpl	%edx,%ecx
	ja		LClampHigh3
LClampReentry3:

	movl	%ebp,snext
	movl	%ecx,tnext

	subl	s,%ebp
	subl	t,%ecx
	
//
// set up advancetable
//
	movl	%ecx,%eax
	movl	%ebp,%edx
	sarl	$19,%edx			// sstep >>= 16;
	movl	C(cachewidth),%ebx
	sarl	$19,%eax			// tstep >>= 16;
	jz		LIsZero
	imull	%ebx,%eax			// (tstep >> 16) * cachewidth;
LIsZero:
	addl	%edx,%eax			// add in sstep
								// (tstep >> 16) * cachewidth + (sstep >> 16);
	movl	tfracf,%edx
	movl	%eax,advancetable+4	// advance base in t
	addl	%ebx,%eax			// ((tstep >> 16) + 1) * cachewidth +
								//  (sstep >> 16);
	shll	$13,%ebp			// left-justify sstep fractional part
	movl	%ebp,sstep
	movl	sfracf,%ebx
	shll	$13,%ecx			// left-justify tstep fractional part
	movl	%eax,advancetable	// advance extra in t
	movl	%ecx,tstep

	movl	pz,%ecx
	movl	izi,%ebp

	cmpw	(%ecx),%bp
	jl		Lp1
	movb	(%esi),%al			// get first source texel
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp1
	movw	%bp,(%ecx)
	movb	%al,(%edi)			// store first dest pixel
Lp1:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx			// advance tfrac fractional part by tstep frac

	sbbl	%eax,%eax			// turn tstep carry into -1 (0 if none)
	addl	sstep,%ebx			// advance sfrac fractional part by sstep frac
	adcl	advancetable+4(,%eax,4),%esi	// point to next source texel

	cmpw	2(%ecx),%bp
	jl		Lp2
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp2
	movw	%bp,2(%ecx)
	movb	%al,1(%edi)
Lp2:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	cmpw	4(%ecx),%bp
	jl		Lp3
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp3
	movw	%bp,4(%ecx)
	movb	%al,2(%edi)
Lp3:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	cmpw	6(%ecx),%bp
	jl		Lp4
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp4
	movw	%bp,6(%ecx)
	movb	%al,3(%edi)
Lp4:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	cmpw	8(%ecx),%bp
	jl		Lp5
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp5
	movw	%bp,8(%ecx)
	movb	%al,4(%edi)
Lp5:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

//
// start FDIV for end of next segment in flight, so it can overlap
//
	popl	%eax
	cmpl	$8,%eax			// more than one segment after this?
	ja		LSetupNotLast2	// yes

	decl	%eax
	jz		LFDIVInFlight2	// if only one pixel, no need to start an FDIV
	movl	%eax,spancountminus1
	fildl	spancountminus1

	flds	C(d_zistepu)		// _d_zistepu | spancountminus1
	fmul	%st(1),%st(0)	// _d_zistepu*scm1 | scm1
	flds	C(d_tdivzstepu)	// _d_tdivzstepu | _d_zistepu*scm1 | scm1
	fmul	%st(2),%st(0)	// _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
	fxch	%st(1)			// _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1
	faddp	%st(0),%st(3)	// _d_tdivzstepu*scm1 | scm1
	fxch	%st(1)			// scm1 | _d_tdivzstepu*scm1
	fmuls	C(d_sdivzstepu)	// _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
	fxch	%st(1)			// _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1
	flds	fp_64k			// 64k | _d_sdivzstepu*scm1
	fxch	%st(1)			// _d_sdivzstepu*scm1 | 64k
	faddp	%st(0),%st(4)	// 64k

	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
							//  overlap
	jmp		LFDIVInFlight2

	.align	4
LSetupNotLast2:
	fadds	zi8stepu
	fxch	%st(2)
	fadds	sdivz8stepu
	fxch	%st(2)
	flds	tdivz8stepu
	faddp	%st(0),%st(2)
	flds	fp_64k
	fdiv	%st(1),%st(0)	// z = 1/1/z
							// this is what we've gone to all this trouble to
							//  overlap
LFDIVInFlight2:
	pushl	%eax

	cmpw	10(%ecx),%bp
	jl		Lp6
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp6
	movw	%bp,10(%ecx)
	movb	%al,5(%edi)
Lp6:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	cmpw	12(%ecx),%bp
	jl		Lp7
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp7
	movw	%bp,12(%ecx)
	movb	%al,6(%edi)
Lp7:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	cmpw	14(%ecx),%bp
	jl		Lp8
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp8
	movw	%bp,14(%ecx)
	movb	%al,7(%edi)
Lp8:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

	addl	$8,%edi
	addl	$16,%ecx
	movl	%edx,tfracf
	movl	snext,%edx
	movl	%ebx,sfracf
	movl	tnext,%ebx
	movl	%edx,s
	movl	%ebx,t

	movl	%ecx,pz
	movl	%ebp,izi

	popl	%ecx				// retrieve count

//
// determine whether last span or not
//
	cmpl	$8,%ecx				// are there multiple segments remaining?
	ja		LNotLastSegment		// yes

//
// last segment of scan
//
LLastSegment:

//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there. The number of pixels left is variable, and we want to land on the
// last pixel, not step one past it, so we can't run into arithmetic problems
//
	testl	%ecx,%ecx
	jz		LNoSteps		// just draw the last pixel and we're done

// pick up after the FDIV that was left in flight previously


	fld		%st(0)			// duplicate it
	fmul	%st(4),%st(0)	// s = s/z * z
	fxch	%st(1)
	fmul	%st(3),%st(0)	// t = t/z * z
	fxch	%st(1)
	fistpl	snext
	fistpl	tnext

	movl	C(tadjust),%ebx
	movl	C(sadjust),%eax

	addl	snext,%eax
	addl	tnext,%ebx

	movl	C(bbextents),%ebp
	movl	C(bbextentt),%edx

	cmpl	$2048,%eax
	jl		LClampLow4
	cmpl	%ebp,%eax
	ja		LClampHigh4
LClampReentry4:
	movl	%eax,snext

	cmpl	$2048,%ebx
	jl		LClampLow5
	cmpl	%edx,%ebx
	ja		LClampHigh5
LClampReentry5:

	cmpl	$1,%ecx			// don't bother 
	je		LOnlyOneStep	// if two pixels in segment, there's only one step,
							//  of the segment length
	subl	s,%eax
	subl	t,%ebx

	addl	%eax,%eax		// convert to 15.17 format so multiply by 1.31
	addl	%ebx,%ebx		//  reciprocal yields 16.48
	imull	reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1)
	movl	%edx,%ebp

	movl	%ebx,%eax
	imull	reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1)

LSetEntryvec:
//
// set up advancetable
//
	movl	spr8entryvec_table(,%ecx,4),%ebx
	movl	%edx,%eax
	pushl	%ebx				// entry point into code for RET later
	movl	%ebp,%ecx
	sarl	$16,%ecx			// sstep >>= 16;
	movl	C(cachewidth),%ebx
	sarl	$16,%edx			// tstep >>= 16;
	jz		LIsZeroLast
	imull	%ebx,%edx			// (tstep >> 16) * cachewidth;
LIsZeroLast:
	addl	%ecx,%edx			// add in sstep
								// (tstep >> 16) * cachewidth + (sstep >> 16);
	movl	tfracf,%ecx
	movl	%edx,advancetable+4	// advance base in t
	addl	%ebx,%edx			// ((tstep >> 16) + 1) * cachewidth +
								//  (sstep >> 16);
	shll	$16,%ebp			// left-justify sstep fractional part
	movl	sfracf,%ebx
	shll	$16,%eax			// left-justify tstep fractional part
	movl	%edx,advancetable	// advance extra in t

	movl	%eax,tstep
	movl	%ebp,sstep
	movl	%ecx,%edx

	movl	pz,%ecx
	movl	izi,%ebp

	ret							// jump to the number-of-pixels handler

//----------------------------------------

LNoSteps:
	movl	pz,%ecx
	subl	$7,%edi			// adjust for hardwired offset
	subl	$14,%ecx
	jmp		LEndSpan


LOnlyOneStep:
	subl	s,%eax
	subl	t,%ebx
	movl	%eax,%ebp
	movl	%ebx,%edx
	jmp		LSetEntryvec

//----------------------------------------

.globl	Spr8Entry2_8
Spr8Entry2_8:
	subl	$6,%edi		// adjust for hardwired offsets
	subl	$12,%ecx
	movb	(%esi),%al
	jmp		LLEntry2_8

//----------------------------------------

.globl	Spr8Entry3_8
Spr8Entry3_8:
	subl	$5,%edi		// adjust for hardwired offsets
	subl	$10,%ecx
	jmp		LLEntry3_8

//----------------------------------------

.globl	Spr8Entry4_8
Spr8Entry4_8:
	subl	$4,%edi		// adjust for hardwired offsets
	subl	$8,%ecx
	jmp		LLEntry4_8

//----------------------------------------

.globl	Spr8Entry5_8
Spr8Entry5_8:
	subl	$3,%edi		// adjust for hardwired offsets
	subl	$6,%ecx
	jmp		LLEntry5_8

//----------------------------------------

.globl	Spr8Entry6_8
Spr8Entry6_8:
	subl	$2,%edi		// adjust for hardwired offsets
	subl	$4,%ecx
	jmp		LLEntry6_8

//----------------------------------------

.globl	Spr8Entry7_8
Spr8Entry7_8:
	decl	%edi		// adjust for hardwired offsets
	subl	$2,%ecx
	jmp		LLEntry7_8

//----------------------------------------

.globl	Spr8Entry8_8
Spr8Entry8_8:
	cmpw	(%ecx),%bp
	jl		Lp9
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp9
	movw	%bp,(%ecx)
	movb	%al,(%edi)
Lp9:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry7_8:
	cmpw	2(%ecx),%bp
	jl		Lp10
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp10
	movw	%bp,2(%ecx)
	movb	%al,1(%edi)
Lp10:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry6_8:
	cmpw	4(%ecx),%bp
	jl		Lp11
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp11
	movw	%bp,4(%ecx)
	movb	%al,2(%edi)
Lp11:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry5_8:
	cmpw	6(%ecx),%bp
	jl		Lp12
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp12
	movw	%bp,6(%ecx)
	movb	%al,3(%edi)
Lp12:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry4_8:
	cmpw	8(%ecx),%bp
	jl		Lp13
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp13
	movw	%bp,8(%ecx)
	movb	%al,4(%edi)
Lp13:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry3_8:
	cmpw	10(%ecx),%bp
	jl		Lp14
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp14
	movw	%bp,10(%ecx)
	movb	%al,5(%edi)
Lp14:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi
LLEntry2_8:
	cmpw	12(%ecx),%bp
	jl		Lp15
	movb	(%esi),%al
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp15
	movw	%bp,12(%ecx)
	movb	%al,6(%edi)
Lp15:
	addl	izistep,%ebp
	adcl	$0,%ebp
	addl	tstep,%edx
	sbbl	%eax,%eax
	addl	sstep,%ebx
	adcl	advancetable+4(,%eax,4),%esi

LEndSpan:
	cmpw	14(%ecx),%bp
	jl		Lp16
	movb	(%esi),%al		// load first texel in segment
	cmpb	$(TRANSPARENT_COLOR),%al
	jz		Lp16
	movw	%bp,14(%ecx)
	movb	%al,7(%edi)
Lp16:

//
// clear s/z, t/z, 1/z from FP stack
//
	fstp %st(0)
	fstp %st(0)
	fstp %st(0)

	popl	%ebx				// restore spans pointer
LNextSpan:
	addl	$(sspan_t_size),%ebx // point to next span
	movl	sspan_t_count(%ebx),%ecx
	cmpl	$0,%ecx				// any more spans?
	jg		LSpanLoop			// yes
	jz		LNextSpan			// yes, but this one's empty

	popl	%ebx				// restore register variables
	popl	%esi
	popl	%edi
	popl	%ebp				// restore the caller's stack frame
	ret
