;*
;* tmap.nas
;* The texture-mapping inner loops in pure assembly language.
;*
;*---------------------------------------------------------------------------
;* Copyright 1998-2006 Randy Heit
;* All rights reserved.
;*
;* Redistribution and use in source and binary forms, with or without
;* modification, are permitted provided that the following conditions
;* are met:
;*
;* 1. Redistributions of source code must retain the above copyright
;*    notice, this list of conditions and the following disclaimer.
;* 2. Redistributions in binary form must reproduce the above copyright
;*    notice, this list of conditions and the following disclaimer in the
;*    documentation and/or other materials provided with the distribution.
;* 3. The name of the author may not be used to endorse or promote products
;*    derived from this software without specific prior written permission.
;*
;* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
;* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
;* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
;* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
;* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
;* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
;* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;*---------------------------------------------------------------------------
;*

BITS 32

; Segment/section definition macros. 

	SECTION .data

%define SPACEFILLER4 (0x44444444)

; If you change this in r_draw.c, be sure to change it here, too!
FUZZTABLE	equ	50

%ifdef M_TARGET_LINUX

EXTERN ylookup
EXTERN centery
EXTERN fuzzpos
EXTERN fuzzoffset
EXTERN NormalLight
EXTERN realviewheight
EXTERN fuzzviewheight
EXTERN CPU

EXTERN dc_pitch
EXTERN dc_colormap
EXTERN dc_iscale
EXTERN dc_texturefrac
EXTERN dc_source
EXTERN dc_yl
EXTERN dc_yh
EXTERN dc_x
EXTERN dc_count
EXTERN dc_dest
EXTERN dc_destorg

EXTERN dc_ctspan
EXTERN dc_temp

EXTERN ds_xstep
EXTERN ds_ystep
EXTERN ds_colormap
EXTERN ds_source
EXTERN ds_x1
EXTERN ds_x2
EXTERN ds_xfrac
EXTERN ds_yfrac
EXTERN ds_y

GLOBAL ds_cursource
GLOBAL ds_curcolormap

%else

EXTERN _ylookup
EXTERN _centery
EXTERN _fuzzpos
EXTERN _fuzzoffset
EXTERN _NormalLight
EXTERN _realviewheight
EXTERN _fuzzviewheight
EXTERN _CPU

EXTERN _dc_pitch
EXTERN _dc_colormap
EXTERN _dc_iscale
EXTERN _dc_texturefrac
EXTERN _dc_source
EXTERN _dc_yl
EXTERN _dc_yh
EXTERN _dc_x
EXTERN _dc_count
EXTERN _dc_dest
EXTERN _dc_destorg

EXTERN _dc_ctspan
EXTERN _dc_temp

EXTERN _ds_xstep
EXTERN _ds_ystep
EXTERN _ds_colormap
EXTERN _ds_source
EXTERN _ds_x1
EXTERN _ds_x2
EXTERN _ds_xfrac
EXTERN _ds_yfrac
EXTERN _ds_y

GLOBAL _ds_cursource
GLOBAL _ds_curcolormap

%define ylookup		_ylookup
%define centery		_centery
%define fuzzpos		_fuzzpos
%define fuzzoffset	_fuzzoffset
%define NormalLight	_NormalLight
%define realviewheight	_realviewheight
%define fuzzviewheight	_fuzzviewheight
%define CPU		_CPU

%define dc_pitch	_dc_pitch
%define dc_colormap	_dc_colormap
%define dc_iscale	_dc_iscale
%define dc_texturefrac	_dc_texturefrac
%define dc_source	_dc_source
%define dc_yl		_dc_yl
%define dc_yh		_dc_yh
%define dc_x		_dc_x
%define dc_count	_dc_count
%define dc_dest		_dc_dest
%define dc_destorg	_dc_destorg

%define dc_ctspan	_dc_ctspan
%define dc_temp		_dc_temp

%define ds_xstep	_ds_xstep
%define ds_ystep	_ds_ystep
%define ds_colormap	_ds_colormap
%define ds_source	_ds_source
%define ds_x1		_ds_x1
%define ds_x2		_ds_x2
%define ds_xfrac	_ds_xfrac
%define ds_yfrac	_ds_yfrac
%define ds_y		_ds_y

%define R_SetSpanSource_ASM	_R_SetSpanSource_ASM
%define R_SetSpanSize_ASM	_R_SetSpanSize_ASM
%define R_SetSpanColormap_ASM	_R_SetSpanColormap_ASM

%endif

_ds_cursource:
ds_cursource:
	DD 0

_ds_curcolormap:
ds_curcolormap:
	DD 0


; Local stuff:
lastAddress	DD 0
pixelcount	DD 0

	SECTION .text


GLOBAL @R_SetSpanSource_ASM@4
GLOBAL R_SetSpanSource_ASM

R_SetSpanSource_ASM:
	mov	ecx,[esp+4]

@R_SetSpanSource_ASM@4:
	mov	[spreada+2],ecx
	mov	[spreadb+2],ecx
	mov	[spreadc+2],ecx
	mov	[spreadd+2],ecx
	mov	[spreade+2],ecx
	mov	[spreadf+2],ecx
	mov	[spreadg+2],ecx

	mov	[mspreada+2],ecx
	mov	[mspreadb+2],ecx
	mov	[mspreadc+2],ecx
	mov	[mspreadd+2],ecx
	mov	[mspreade+2],ecx
	mov	[mspreadf+2],ecx
	mov	[mspreadg+2],ecx

	mov	[ds_cursource],ecx
	ret

GLOBAL @R_SetSpanColormap_ASM@4
GLOBAL R_SetSpanColormap_ASM

R_SetSpanColormap_ASM:
	mov ecx,[esp+4]

@R_SetSpanColormap_ASM@4:
	mov	[spmapa+2],ecx
	mov	[spmapb+2],ecx
	mov	[spmapc+2],ecx
	mov	[spmapd+2],ecx
	mov	[spmape+2],ecx
	mov	[spmapf+2],ecx
	mov	[spmapg+2],ecx

	mov	[mspmapa+2],ecx
	mov	[mspmapb+2],ecx
	mov	[mspmapc+2],ecx
	mov	[mspmapd+2],ecx
	mov	[mspmape+2],ecx
	mov	[mspmapf+2],ecx
	mov	[mspmapg+2],ecx

	mov	[ds_curcolormap],ecx
	ret

GLOBAL R_SetSpanSize_ASM

EXTERN	SetTiltedSpanSize

R_SetSpanSize_ASM:
	mov	edx,[esp+4]
	mov	ecx,[esp+8]
	call	SetTiltedSpanSize
	
	mov	[dsy1+2],dl
	mov	[dsy2+2],dl
	
	mov	[dsx1+2],cl
	mov	[dsx2+2],cl
	mov	[dsx3+2],cl
	mov	[dsx4+2],cl
	mov	[dsx5+2],cl
	mov	[dsx6+2],cl
	mov	[dsx7+2],cl
	
	mov	[dmsy1+2],dl
	mov	[dmsy2+2],dl
	
	mov	[dmsx1+2],cl
	mov	[dmsx2+2],cl
	mov	[dmsx3+2],cl
	mov	[dmsx4+2],cl
	mov	[dmsx5+2],cl
	mov	[dmsx6+2],cl
	mov	[dmsx7+2],cl

	push	ecx
	add	ecx,edx
	mov	eax,1
	shl	eax,cl
	dec	eax
	mov	[dsm1+2],eax
	mov	[dsm5+1],eax
	mov	[dsm6+1],eax
	mov	[dsm7+1],eax
	
	mov	[dmsm1+2],eax
	mov	[dmsm5+1],eax
	mov	[dmsm6+1],eax
	mov	[dmsm7+1],eax
	pop	ecx
	ror	eax,cl
	mov	[dsm2+2],eax
	mov	[dsm3+2],eax
	mov	[dsm4+2],eax

	mov	[dmsm2+2],eax
	mov	[dmsm3+2],eax
	mov	[dmsm4+2],eax
	and	eax,0xffff
	not	eax
	mov	[dsm8+2],eax
	mov	[dsm9+2],eax

	mov	[dmsm8+2],eax
	mov	[dmsm9+2],eax
	
	neg	dl
	mov	[dsy3+2],dl
	mov	[dsy4+2],dl

	mov	[dmsy3+2],dl
	mov	[dmsy4+2],dl
	
aret:	ret

	SECTION .rtext	progbits alloc exec write align=64

GLOBAL @R_DrawSpanP_ASM@0
GLOBAL _R_DrawSpanP_ASM
GLOBAL R_DrawSpanP_ASM

; eax: scratch
; ebx: zero
; ecx: yfrac at top end, xfrac int part at low end
; edx: xfrac frac part at top end
; edi: dest
; ebp: scratch
; esi: count

	align	16

@R_DrawSpanP_ASM@0:
_R_DrawSpanP_ASM:
R_DrawSpanP_ASM:
	mov	eax,[ds_x2]
	 mov	ecx,[ds_x1]
	sub	eax,ecx
	 jl	aret		; count < 0: nothing to do, so leave

	push	ebx
	push	edi
	push	ebp
	push	esi

	mov	edi,ecx
	add	edi,[dc_destorg]
	 mov	ecx,[ds_y]
	add	edi,[ylookup+ecx*4]
	 mov	edx,[ds_xstep]
dsy1:	shl	edx,6
	 mov	ebp,[ds_xstep]
dsy3:	shr	ebp,26
	 xor	ebx,ebx
	lea	esi,[eax+1]
	 mov	[ds_xstep],edx
	mov	edx,[ds_ystep]
	 mov	ecx,[ds_xfrac]
dsy4:	shr	ecx,26
dsm8:	 and	edx,0xffffffc0
	or	ebp,edx
	 mov	[ds_ystep],ebp
	mov	ebp,[ds_yfrac]
	 mov	edx,[ds_xfrac]
dsy2:	shl	edx,6
dsm9:	 and	ebp,0xffffffc0
	or	ecx,ebp
	 shr	esi,1
	jnc	dseven1

; do odd pixel

		mov	ebp,ecx
dsx1:		rol	ebp,6
dsm1:		and	ebp,0xfff
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
spreada		 mov	bl,[ebp+SPACEFILLER4]
spmapa		mov	bl,[ebx+SPACEFILLER4]
		mov	[edi],bl
		 inc	edi

dseven1		shr	esi,1
		 jnc	dsrest

; do two more pixels
		mov	ebp,ecx
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
dsm2:		 and	ebp,0xfc00003f
dsx2:		rol	ebp,6
		mov	eax,ecx
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
spreadb		 mov	bl,[ebp+SPACEFILLER4]	;read texel1
dsx3:		rol	eax,6
dsm6:		and	eax,0xfff
spmapb		 mov	bl,[ebx+SPACEFILLER4]	;map texel1
		mov	[edi],bl		;store texel1
		 add	edi,2
spreadc		mov	bl,[eax+SPACEFILLER4]	;read texel2
spmapc		mov	bl,[ebx+SPACEFILLER4]	;map texel2
		mov	[edi-1],bl		;store texel2

; do the rest

dsrest		test	esi,esi
		jz near	dsdone

		align 16

dsloop		mov	ebp,ecx
spstep1d	 add	edx,[ds_xstep]
spstep2d	adc	ecx,[ds_ystep]
dsm3:		 and	ebp,0xfc00003f
dsx4:		rol	ebp,6
		mov	eax,ecx
spstep1e	 add	edx,[ds_xstep]
spstep2e	adc	ecx,[ds_ystep]
spreadd		 mov	bl,[ebp+SPACEFILLER4]	;read texel1
dsx5:		rol	eax,6
dsm5:		and	eax,0xfff
spmapd		 mov	bl,[ebx+SPACEFILLER4]	;map texel1
		mov	[edi],bl		;store texel1
		 mov	ebp,ecx
spreade		mov	bl,[eax+SPACEFILLER4]	;read texel2
spstep1f	 add	edx,[ds_xstep]
spstep2f	adc	ecx,[ds_ystep]
dsm4:		 and	ebp,0xfc00003f
dsx6:		rol	ebp,6
spmape		mov	bl,[ebx+SPACEFILLER4]	;map texel2
		 mov	eax,ecx
		mov	[edi+1],bl		;store texel2
spreadf		 mov	bl,[ebp+SPACEFILLER4]	;read texel3
spmapf		mov	bl,[ebx+SPACEFILLER4]	;map texel3
		 add	edi,4
dsx7:		rol	eax,6
dsm7:		and	eax,0xfff
		 mov	[edi-2],bl		;store texel3
spreadg		mov	bl,[eax+SPACEFILLER4]	;read texel4
spstep1g	 add	edx,[ds_xstep]
spstep2g	adc	ecx,[ds_ystep]
spmapg		 mov	bl,[ebx+SPACEFILLER4]	;map texel4
		dec	esi
		 mov	[edi-1],bl		;store texel4
		jnz near dsloop

dsdone	pop	esi
	pop	ebp
	pop	edi
	pop	ebx

rdspret	ret

; This is the same as the previous routine, except it doesn't draw pixels
; where the texture's color value is 0.

GLOBAL @R_DrawSpanMaskedP_ASM@0
GLOBAL _R_DrawSpanMaskedP_ASM
GLOBAL R_DrawSpanMaskedP_ASM

; eax: scratch
; ebx: zero
; ecx: yfrac at top end, xfrac int part at low end
; edx: xfrac frac part at top end
; edi: dest
; ebp: scratch
; esi: count

	align	16

@R_DrawSpanMaskedP_ASM@0:
_R_DrawSpanMaskedP_ASM:
R_DrawSpanMaskedP_ASM:
	mov	eax,[ds_x2]
	 mov	ecx,[ds_x1]
	sub	eax,ecx
	 jl	rdspret		; count < 0: nothing to do, so leave

	push	ebx
	push	edi
	push	ebp
	push	esi

	mov	edi,ecx
	add	edi,[dc_destorg]
	 mov	ecx,[ds_y]
	add	edi,[ylookup+ecx*4]
	 mov	edx,[ds_xstep]
dmsy1:	shl	edx,6
	 mov	ebp,[ds_xstep]
dmsy3:	shr	ebp,26
	 xor	ebx,ebx
	lea	esi,[eax+1]
	 mov	[ds_xstep],edx
	mov	edx,[ds_ystep]
	 mov	ecx,[ds_xfrac]
dmsy4:	shr	ecx,26
dmsm8:	 and	edx,0xffffffc0
	or	ebp,edx
	 mov	[ds_ystep],ebp
	mov	ebp,[ds_yfrac]
	 mov	edx,[ds_xfrac]
dmsy2:	shl	edx,6
dmsm9:	 and	ebp,0xffffffc0
	or	ecx,ebp
	 shr	esi,1
	jnc	dmseven1

; do odd pixel

		mov	ebp,ecx
dmsx1:		rol	ebp,6
dmsm1:		and	ebp,0xfff
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
mspreada	 mov	bl,[ebp+SPACEFILLER4]
		cmp	bl,0
		 je	mspskipa
mspmapa		mov	bl,[ebx+SPACEFILLER4]
		mov	[edi],bl
mspskipa:	 inc	edi

dmseven1	shr	esi,1
		 jnc	dmsrest

; do two more pixels
		mov	ebp,ecx
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
dmsm2:		 and	ebp,0xfc00003f
dmsx2:		rol	ebp,6
		mov	eax,ecx
		 add	edx,[ds_xstep]
		adc	ecx,[ds_ystep]
mspreadb	 mov	bl,[ebp+SPACEFILLER4]	;read texel1
dmsx3:		rol	eax,6
dmsm6:		and	eax,0xfff
		cmp	bl,0
		 je	mspskipb
mspmapb		 mov	bl,[ebx+SPACEFILLER4]	;map texel1
		mov	[edi],bl		;store texel1
mspskipb	 add	edi,2
mspreadc	mov	bl,[eax+SPACEFILLER4]	;read texel2
		cmp	bl,0
		 je	dmsrest
mspmapc		mov	bl,[ebx+SPACEFILLER4]	;map texel2
		mov	[edi-1],bl		;store texel2

; do the rest

dmsrest		test	esi,esi
		jz near	dmsdone

		align 16

dmsloop		mov	ebp,ecx
mspstep1d	 add	edx,[ds_xstep]
mspstep2d	adc	ecx,[ds_ystep]
dmsm3:		 and	ebp,0xfc00003f
dmsx4:		rol	ebp,6
		mov	eax,ecx
mspstep1e	 add	edx,[ds_xstep]
mspstep2e	adc	ecx,[ds_ystep]
mspreadd	 mov	bl,[ebp+SPACEFILLER4]	;read texel1
dmsx5:		rol	eax,6
dmsm5:		and	eax,0xfff
		 cmp	bl,0
		mov	ebp,ecx
		 je	mspreade
mspmapd		mov	bl,[ebx+SPACEFILLER4]	;map texel1
		mov	[edi],bl		;store texel1
mspreade	mov	bl,[eax+SPACEFILLER4]	;read texel2
mspstep1f	 add	edx,[ds_xstep]
mspstep2f	adc	ecx,[ds_ystep]
dmsm4:		 and	ebp,0xfc00003f
dmsx6:		rol	ebp,6
		 cmp	bl,0
		mov	eax,ecx
		 je	mspreadf
mspmape		mov	bl,[ebx+SPACEFILLER4]	;map texel2
		mov	[edi+1],bl		;store texel2
mspreadf	 mov	bl,[ebp+SPACEFILLER4]	;read texel3
		add	edi,4
dmsx7:		rol	eax,6
dmsm7:		and	eax,0xfff
		cmp	bl,0
		 je	mspreadg
mspmapf		mov	bl,[ebx+SPACEFILLER4]	;map texel3
		 mov	[edi-2],bl		;store texel3
mspreadg	mov	bl,[eax+SPACEFILLER4]	;read texel4
mspstep1g	 add	edx,[ds_xstep]
mspstep2g	adc	ecx,[ds_ystep]
		cmp	bl,0
		 je	mspskipg
mspmapg		 mov	bl,[ebx+SPACEFILLER4]	;map texel4
		mov	[edi-1],bl		;store texel4
mspskipg	dec	esi
		 jnz near dmsloop

dmsdone	pop	esi
	pop	ebp
	pop	edi
	pop	ebx

	ret




;*----------------------------------------------------------------------
;*
;* R_DrawColumnP
;*
;*----------------------------------------------------------------------

GLOBAL	@R_DrawColumnP_ASM@0
GLOBAL	_R_DrawColumnP_ASM
GLOBAL	R_DrawColumnP_ASM

	align 16

R_DrawColumnP_ASM:
_R_DrawColumnP_ASM:
@R_DrawColumnP_ASM@0:

; count = dc_yh - dc_yl;

	mov	ecx,[dc_count]
	test	ecx,ecx
	jle	near rdcpret		; count <= 0: nothing to do, so leave

	push	ebp			; save registers
	 push	ebx
	push	edi
	 push	esi

; dest = ylookup[dc_yl] + dc_x + dc_destorg;

	mov	edi,[dc_dest]
	mov	ebp,ecx
	mov	ebx,[dc_texturefrac]	; ebx = frac
rdcp1:	sub	edi,SPACEFILLER4
	mov	ecx,ebx
	shr	ecx,16
	mov	esi,[dc_source]
	mov	edx,[dc_iscale]
	mov	eax,[dc_colormap]

	cmp	BYTE [CPU+66],byte 5
	jg	rdcploop2

; need 12 bytes of filler to make it aligned
	db	0x8D,0x80,0,0,0,0	; lea eax,[eax+00000000]
	db	0x8D,0xBF,0,0,0,0	; lea edi,[edi+00000000]

	align 16

; The registers should now look like this:
;
;	[31  ..  16][15 .. 8][7 .. 0]
; eax	[colormap		    ]
; ebx	[yi	   ][yf		    ]
; ecx	[scratch		    ]
; edx	[dyi	   ][dyf	    ]
; esi	[source texture column	    ]
; edi	[destination screen pointer ]
; ebp	[counter		    ]
;


; Note the partial register stalls on anything better than a Pentium
; That's why there are two versions of this loop.

rdcploop:
	mov	cl,[esi+ecx]		; Fetch texel
	 xor	ch,ch
	add	ebx,edx			; increment frac
rdcp2:	 add	edi,SPACEFILLER4	; increment destination pointer
	mov	cl,[eax+ecx]		; colormap texel
	mov	[edi],cl		; Store texel
	 mov	ecx,ebx
	shr	ecx,16
	 dec	ebp
	jnz	rdcploop		; loop

	pop	esi
	 pop	edi
	pop	ebx
	 pop	ebp
rdcpret:
	ret
	
	align 16

rdcploop2:
	movzx	ecx,byte [esi+ecx]	; Fetch texel
	add	ebx,edx			; increment frac
	mov	cl,[eax+ecx]		; colormap texel
rdcp3:	add	edi,SPACEFILLER4	; increment destination pointer
	mov	[edi],cl		; Store texel
	mov	ecx,ebx
	shr	ecx,16
	dec	ebp
	jnz	rdcploop2		; loop

	pop	esi
	pop	edi
	pop	ebx
	pop	ebp
	ret
	


;*----------------------------------------------------------------------
;*
;* R_DrawFuzzColumnP
;*
;*----------------------------------------------------------------------

GLOBAL	@R_DrawFuzzColumnP_ASM@0
GLOBAL	_R_DrawFuzzColumnP_ASM
GLOBAL	R_DrawFuzzColumnP_ASM

	align 16

R_DrawFuzzColumnP_ASM:
_R_DrawFuzzColumnP_ASM:
@R_DrawFuzzColumnP_ASM@0:

; Adjust borders. Low...
	mov	eax,[dc_yl]
	 push	ebx
	push	esi
	 push	edi
	push	ebp

	 cmp	eax,0
	jg	.ylok

	mov	eax,1
	nop

; ...and high.
.ylok	mov	edx,[fuzzviewheight]
	 mov	esi,[dc_yh]
	cmp	esi,edx
	 jle	.yhok

	mov	esi,edx
	nop

.yhok	mov	edx,[dc_x]
	 sub	esi,eax			; esi = count
	js	near .dfcdone		; Zero length (or less)

	mov	edi,[ylookup+eax*4]
	 mov	ebx,edx
	add	edi,[dc_destorg]
	 mov	eax,[NormalLight]
	mov	ecx,[fuzzpos]
	 add	edi,ebx
	add	eax,256*6
	 inc	esi
	mov	ebp,[dc_pitch]
	 mov	edx,FUZZTABLE
	test	ecx,ecx
	 je	.fuzz0

;
; esi = count
; edi = dest
; ecx = fuzzpos
; eax = colormap 6
;

; first loop: end with fuzzpos or count 0, whichever happens first

	sub	edx,ecx			; edx = # of entries left in fuzzoffset
	 mov	ebx,esi
	cmp	esi,edx
	 jle	.enuf
	mov	esi,edx
.enuf	sub	ebx,esi
	 mov	edx,[fuzzoffset+ecx*4]
	push	ebx
	 xor	ebx,ebx

.loop1	inc	ecx
	 mov	bl,[edi+edx]
	dec	esi
	 mov	bl,[eax+ebx]
	mov	[edi],bl
	 lea	edi,[edi+ebp]
	mov	edx,[fuzzoffset+ecx*4]
	 jnz	.loop1

; second loop: Chunk it into groups of FUZZTABLE-sized spans and do those

	pop	esi
	 cmp	ecx,FUZZTABLE
	jl	.savefuzzpos
	xor	ecx,ecx
	 nop
.fuzz0	cmp	esi,FUZZTABLE
	 jl	.chunked

.oloop	lea	edx,[esi-FUZZTABLE]
	 mov	esi,FUZZTABLE
	push	edx
	 mov	edx,[fuzzoffset+ecx*4]

.iloop	inc	ecx
	 mov	bl,[edi+edx]
	dec	esi
	 mov	bl,[eax+ebx]
	mov	[edi],bl
	 lea	edi,[edi+ebp]
	mov	edx,[fuzzoffset+ecx*4]
	 jnz	.iloop

	pop	esi
	 xor	ecx,ecx
	cmp	esi,FUZZTABLE
	 jge	.oloop

; third loop: Do whatever is left

.chunked
	test	esi,esi
	 jle	.savefuzzpos
	mov	edx,[fuzzoffset+ecx*4]
	 nop

.loop3	inc	ecx
	 mov	bl,[edi+edx]
	dec	esi
	 mov	bl,[eax+ebx]
	mov	[edi],bl
	 lea	edi,[edi+ebp]
	mov	edx,[fuzzoffset+ecx*4]
	 jnz	.loop3

.savefuzzpos:
	mov	[fuzzpos],ecx
.dfcdone:
	pop	ebp
	pop	edi
	pop	esi
	pop	ebx
	ret


;*----------------------------------------------------------------------
;*
;* R_DrawColumnHorizP_ASM
;*
;*----------------------------------------------------------------------

GLOBAL	@R_DrawColumnHorizP_ASM@0
GLOBAL	_R_DrawColumnHorizP_ASM
GLOBAL	R_DrawColumnHorizP_ASM

	align 16

@R_DrawColumnHorizP_ASM@0:
R_DrawColumnHorizP_ASM:
_R_DrawColumnHorizP_ASM:

; count = dc_yh - dc_yl;

	mov	eax,[dc_yh]
	mov	ecx,[dc_yl]
	sub	eax,ecx
	mov	edx,[dc_x]

	jl	near .leave		; count < 0: nothing to do, so leave

	push	ebp			; save registers
	push	ebx
	push	edi
	push	esi

	inc	eax			; make 0 count mean 0 pixels
	 and	edx,3
	push	eax
	 mov	esi,[dc_ctspan+edx*4]
	lea	eax,[dc_temp+ecx*4+edx] ; eax = top of column in buffer
	 mov	ebp,[dc_yh]
	mov	[esi],ecx
	 mov	[esi+4],ebp
	add	esi,8
	 mov	edi,[dc_source]
	mov	[dc_ctspan+edx*4],esi
	 mov	esi,[dc_iscale]
	mov	ecx,[dc_texturefrac]	; ecx = frac
	 mov	dl,[edi]		; load cache
	mov	ebx,[esp]
	 and	ebx,0xfffffff8
	jnz	.mthan8

; Register usage in the following code is:
;
; eax: dest
; edi: source
; ecx: frac (16.16)
; esi: fracstep (16.16)
; ebx: add1
; ebp: add2
;  dl: texel1
;  dh: texel2
;[esp] count

; there are fewer than 8 pixels to draw

	mov	ebx,[esp]
.lthan8	shr	ebx,1
	 jnc	.even

; do one pixel before loop (little opportunity for pairing)

	mov	ebp,ecx			; copy frac to ebx
	 add	ecx,esi			; increment frac
	shr	ebp,16			; shift frac over to low end
	 add	eax,4
	mov	dl,[edi+ebp]
	mov	[eax-4],dl

.even	test	ebx,ebx
	jz	near .done

.loop2	mov	[esp],ebx		; save counter
	 mov	ebx,ecx			; copy frac for texel1 to ebx
	shr	ebx,16			; shift frac for texel1 to low end
	 add	ecx,esi			; increment frac
	mov	ebp,ecx			; copy frac for texel2 to ebp
	shr	ebp,16			; shift frac for texel2 to low end
	 add	ecx,esi			; increment frac
	 mov	dl,[edi+ebx]		; read texel1
	mov	ebx,[esp]		; fetch counter
	 mov	dh,[edi+ebp]		; read texel2
	mov	[eax],dl		; write texel1
	 mov	[eax+4],dh		; write texel2
	add	eax,8			; increment dest
	 dec	ebx			; decrement counter
	jnz	.loop2			; loop until it hits 0

	jmp	.done

; there are more than 8 pixels to draw. position eax as close to a 32 byte
; boundary as possible, then do whatever is left.

.mthan8 test	eax,4
	jz	.try2

	mov	ebp,ecx			; frac: in ebp
	 add	ecx,esi			; step
	shr	ebp,16			; frac: shift
	 add	eax,4			; increment dest
	 mov	ebx,[esp]		; fetch counter
	mov	dl,[edi+ebp]		; tex:  read
	 dec	ebx			; decrement counter
	mov	[eax-4],dl		; tex:  write
	 mov	[esp],ebx		; store counter

.try2	test	eax,8
	jz	.try4

	mov	ebx,ecx			; frac1: in ebx
	 add	ecx,esi			; step
	shr	ebx,16			; frac1: shift
	 mov	ebp,ecx			; frac2: in ebp
	shr	ebp,16			; frac2: shift
	 add	ecx,esi			; step
	mov	dl,[edi+ebx]		; tex1:  read
	 mov	ebx,[esp]		; fetch counter
	mov	dh,[edi+ebp]		; tex2:  read
	 mov	[eax],dl		; tex1:  write
	mov	[eax+4],dh		; tex2:  write
	 sub	ebx,2			; decrement counter
	add	eax,8			; increment dest
	 mov	[esp],ebx		; store counter

.try4	test	eax,16
	jz	.try8

	mov	ebx,ecx			; frac1: in ebx
	 add	ecx,esi			; step
	shr	ebx,16			; frac1: shift
	 mov	ebp,ecx			; frac2: in ebp
	shr	ebp,16			; frac2: shift
	 add	ecx,esi			; step
	mov	dl,[edi+ebx]		; tex1:  read
	 mov	ebx,ecx			; frac3: in ebx
	shr	ebx,16			; frac3: shift
	 mov	dh,[edi+ebp]		; tex2:  read
	add	ecx,esi			; step
	 mov	[eax],dl		; tex1:  write
	mov	[eax+4],dh		; tex2:  write
	 mov	ebp,ecx			; frac4: in ebp
	shr	ebp,16			; frac4: shift
	 add	ecx,esi			; step
	mov	dl,[edi+ebx]		; tex3:  read
	 mov	ebx,[esp]		; fetch counter
	mov	dh,[edi+ebp]		; tex4:  read
	 sub	ebx,4			; decrement counter
	mov	[esp],ebx		; store counter
	 mov	[eax+8],dl		; tex3:  write
	mov	[eax+12],dh		; tex4:  write
	 add	eax,16			; increment dest

.try8	mov	ebx,[esp]		; make counter count groups of 8
	sub	esp,4
	shr	ebx,3
	jmp	.tail8

	align	16

.loop8	mov	[esp],ebx		; save counter
	 mov	ebx,ecx			; frac1: in ebx
	shr	ebx,16			; frac1: shift
	 add	ecx,esi			; step
	mov	ebp,ecx			; frac2: in ebp
	shr	ebp,16			; frac2: shift
	 add	ecx,esi			; step
	 mov	dl,[edi+ebx]		; tex1:  read
	mov	ebx,ecx			; frac3: in ebx
	 mov	dh,[edi+ebp]		; tex2:  read
	shr	ebx,16			; frac3: shift
	 add	ecx,esi			; step
	mov	[eax],dl		; tex1:  write
	 mov	[eax+4],dh		; tex2:  write
	mov	ebp,ecx			; frac4: in ebp
	shr	ebp,16			; frac4: shift
	 add	ecx,esi			; step
	 mov	dl,[edi+ebx]		; tex3:  read
	mov	ebx,ecx			; frac5: in ebx
	 mov	dh,[edi+ebp]		; tex4:  read
	shr	ebx,16			; frac5: shift
	 mov	[eax+8],dl		; tex3:  write
	mov	[eax+12],dh		; tex4:  write
	 add	ecx,esi			; step
	mov	ebp,ecx			; frac6: in ebp
	shr	ebp,16			; frac6: shift
	 mov	dl,[edi+ebx]		; tex5:  read
	 add	ecx,esi			; step
	mov	ebx,ecx			; frac7: in ebx
	 mov	[eax+16],dl		; tex5:  write
	shr	ebx,16			; frac7: shift
	 mov	dh,[edi+ebp]		; tex6:  read
	 add	ecx,esi			; step
	mov	ebp,ecx			; frac8: in ebp
	 mov	[eax+20],dh		; tex6:  write
	shr	ebp,16			; frac8: shift
	 add	eax,32			; increment dest pointer
	 mov	dl,[edi+ebx]		; tex7:  read
	mov	ebx,[esp]		; fetch counter
	 mov	[eax-8],dl		; tex7:  write
	mov	dh,[edi+ebp]		; tex8:  read
	 add	ecx,esi			; step
	mov	[eax-4],dh		; tex8:  write
	 mov	dl,[eax]		; load cache
	dec	ebx			; decrement counter
.tail8	 jnz	near .loop8		; loop if more to do
	
	pop	ebp
	mov	ebx,[esp]
	and	ebx,7
	jnz	near .lthan8

.done	pop	eax
	pop	esi
	pop	edi
	pop	ebx
	pop	ebp
.leave	ret


;*----------------------------------------------------------------------
;*
;* rt_copy1col_asm
;*
;* ecx = hx
;* edx = sx
;* [esp+4] = yl
;* [esp+8] = yh
;*
;*----------------------------------------------------------------------

GLOBAL	@rt_copy1col_asm@16
GLOBAL	_rt_copy1col_asm
GLOBAL	rt_copy1col_asm

	align 16

rt_copy1col_asm:
_rt_copy1col_asm:
	pop	eax
	mov	edx,[esp+4*3]
	mov	ecx,[esp+4*2]
	push	edx
	push	ecx
	mov	ecx,[esp+4*2]
	mov	edx,[esp+4*3]
	push	eax

@rt_copy1col_asm@16:
	mov	eax, [esp+4]
	push	ebx
	mov	ebx, [esp+12]
	push	esi
	sub	ebx, eax
	push	edi
	js	.done

	lea	esi,[eax*4]
	inc	ebx			; ebx = count
	mov	eax,edx
	lea	ecx,[dc_temp+ecx+esi]	; ecx = source
	mov	edi,[ylookup+esi]
	mov	esi,[dc_pitch]		; esi = pitch
	add	eax,edi			; eax = dest
	add	eax,[dc_destorg]

	shr	ebx,1
	jnc	.even

	mov	dl,[ecx]
	add	ecx,4
	mov	[eax],dl
	add	eax,esi

.even	and	ebx,ebx
	jz	.done

.loop	mov	dl,[ecx]
	mov	dh,[ecx+4]
	mov	[eax],dl
	mov	[eax+esi],dh
	add	ecx,8
	lea	eax,[eax+esi*2]
	dec	ebx
	jnz	.loop

.done	pop	edi
	pop	esi
	pop	ebx
	ret	8

;*----------------------------------------------------------------------
;*
;* rt_copy4cols_asm
;*
;* ecx = sx
;* edx = yl
;* [esp+4] = yh
;*
;*----------------------------------------------------------------------

GLOBAL	@rt_copy4cols_asm@12
GLOBAL	_rt_copy4cols_asm
GLOBAL	rt_copy4cols_asm

	align 16

rt_copy4cols_asm:
_rt_copy4cols_asm:
	pop	eax
	mov	ecx,[esp+8]
	mov	edx,[esp+4]
	push	ecx
	mov	ecx,[esp+4]
	push	eax

@rt_copy4cols_asm@12:
	push	ebx
	mov	ebx,[esp+8]
	push	esi
	sub	ebx,edx
	push	edi
	js	.done

	inc	ebx			; ebx = count
	mov	eax,ecx
	mov	esi,[ylookup+edx*4]
	lea	ecx,[dc_temp+edx*4]	; ecx = source
	mov	edx,[dc_pitch]		; edx = pitch
	add	eax,esi			; eax = dest
	add	eax,[dc_destorg]

	shr	ebx,1
	jnc	.even

	mov	esi,[ecx]
	add	ecx,4
	mov	[eax],esi
	add	eax,edx

.even	and	ebx,ebx
	jz	.done

.loop	mov	esi,[ecx]
	mov	edi,[ecx+4]
	mov	[eax],esi
	mov	[eax+edx],edi
	add	ecx,8
	lea	eax,[eax+edx*2]
	dec	ebx
	jnz	.loop

.done	pop	edi
	pop	esi
	pop	ebx
	ret	4

;*----------------------------------------------------------------------
;*
;* rt_map1col_asm
;*
;* ecx = hx
;* edx = sx
;* [esp+4] = yl
;* [esp+8] = yh
;*
;*----------------------------------------------------------------------

GLOBAL	@rt_map1col_asm@16
GLOBAL	_rt_map1col_asm
GLOBAL	rt_map1col_asm

	align 16

rt_map1col_asm:
_rt_map1col_asm:
	pop	eax
	mov	edx,[esp+4*3]
	mov	ecx,[esp+4*2]
	push	edx
	push	ecx
	mov	ecx,[esp+4*2]
	mov	edx,[esp+4*3]
	push	eax

@rt_map1col_asm@16:	
	mov	eax,[esp+4]
	push	ebx
	mov	ebx,[esp+12]
	push	ebp
	push	esi
	sub	ebx, eax
	push	edi
	js	.done

	lea	edi,[eax*4]
	mov	esi,[dc_colormap]		; esi = colormap
	inc	ebx				; ebx = count
	mov	eax,edx
	lea	ebp,[dc_temp+ecx+edi]		; ebp = source
	mov	ecx,[ylookup+edi]
	mov	edi,[dc_pitch]			; edi = pitch
	add	eax,ecx				; eax = dest
	xor	ecx,ecx
	xor	edx,edx
	add	eax,[dc_destorg]

	shr	ebx,1
	jnc	.even

	mov	dl,[ebp]
	add	ebp,4
	mov	dl,[esi+edx]
	mov	[eax],dl
	add	eax,edi

.even	and	ebx,ebx
	jz	.done

.loop	mov	dl,[ebp]
	mov	cl,[ebp+4]
	add	ebp,8
	mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	mov	[eax],dl
	mov	[eax+edi],cl
	dec	ebx
	lea	eax,[eax+edi*2]
	jnz	.loop

.done	pop	edi
	pop	esi
	pop	ebp
	pop	ebx
	ret	8

;*----------------------------------------------------------------------
;*
;* rt_map4cols_asm
;*
;* rt_map4cols_asm1 is for PPro and above
;* rt_map4cols_asm2 is for Pentium and below
;*
;* ecx = sx
;* edx = yl
;* [esp+4] = yh
;*
;*----------------------------------------------------------------------

GLOBAL	@rt_map4cols_asm1@12
GLOBAL	_rt_map4cols_asm1
GLOBAL	rt_map4cols_asm1

	align 16

rt_map4cols_asm1:
_rt_map4cols_asm1:
	pop	eax
	mov	ecx,[esp+8]
	mov	edx,[esp+4]
	push	ecx
	mov	ecx,[esp+4]
	push	eax

@rt_map4cols_asm1@12:
	push	ebx
	mov	ebx,[esp+8]
	push	ebp
	push	esi
	sub	ebx,edx
	push	edi
	js	near .done

	mov	esi,[dc_colormap]	; esi = colormap
	shl	edx,2
	mov	eax,ecx
	inc	ebx			; ebx = count
	mov	edi,[ylookup+edx]
	lea	ebp,[dc_temp+edx]	; ebp = source
	add	eax,edi			; eax = dest
	mov	edi,[dc_pitch]		; edi = pitch
	add	eax,[dc_destorg]
	xor	ecx,ecx
	xor	edx,edx

	shr	ebx,1
	jnc	.even

	mov	dl,[ebp]
	 mov	cl,[ebp+1]
	add	ebp,4
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax],dl
	mov	[eax+1],cl
	 mov	dl,[ebp-2]
	mov	cl,[ebp-1]
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax+2],dl
	mov	[eax+3],cl
	 add	eax,edi

.even	and	ebx,ebx
	jz	.done

.loop
	mov	dl,[ebp]
	 mov	cl,[ebp+1]
	add	ebp,8
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax],dl
	mov	[eax+1],cl
	 mov	dl,[ebp-6]
	mov	cl,[ebp-5]
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax+2],dl
	mov	[eax+3],cl
	 mov	dl,[ebp-4]
	mov	cl,[ebp-3]
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax+edi],dl
	mov	[eax+edi+1],cl
	 mov	dl,[ebp-2]
	mov	cl,[ebp-1]
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax+edi+2],dl
	mov	[eax+edi+3],cl
	 lea	eax,[eax+edi*2]
	dec	ebx

	jnz	.loop

.done	pop	edi
	pop	esi
	pop	ebp
	pop	ebx
	ret	4

GLOBAL	@rt_map4cols_asm2@12
GLOBAL	_rt_map4cols_asm2
GLOBAL	rt_map4cols_asm2

	align 16

rt_map4cols_asm2:
_rt_map4cols_asm2:
	pop	eax
	mov	ecx,[esp+8]
	mov	edx,[esp+4]
	push	ecx
	mov	ecx,[esp+4]
	push	eax

@rt_map4cols_asm2@12:
	push	ebx
	mov	ebx,[esp+8]
	push	ebp
	push	esi
	sub	ebx,edx
	push	edi
	js	near .done

	mov	esi,[dc_colormap]	; esi = colormap
	shl	edx,2
	mov	eax,ecx
	inc	ebx			; ebx = count
	mov	edi,[ylookup+edx]
	lea	ebp,[dc_temp+edx]	; ebp = source
	add	eax,edi			; eax = dest
	mov	edi,[dc_pitch]		; edi = pitch
	add	eax,[dc_destorg]
	xor	ecx,ecx
	xor	edx,edx

	shr	ebx,1
	jnc	.even

	mov	dl,[ebp]
	 mov	cl,[ebp+1]
	add	ebp,4
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax],dl
	mov	[eax+1],cl
	 mov	dl,[ebp-2]
	mov	cl,[ebp-1]
	 mov	dl,[esi+edx]
	mov	cl,[esi+ecx]
	 mov	[eax+2],dl
	mov	[eax+3],cl
	 add	eax,edi

.even	and	ebx,ebx
	jz	.done

.loop
	mov	dl,[ebp+3]
	mov	ch,[esi+edx]
	mov	dl,[ebp+2]
	mov	cl,[esi+edx]
	shl	ecx,16
	mov	dl,[ebp+1]
	mov	ch,[esi+edx]
	mov	dl,[ebp]
	mov	cl,[esi+edx]
	mov	[eax],ecx
	add	eax,edi

	mov	dl,[ebp+7]
	mov	ch,[esi+edx]
	mov	dl,[ebp+6]
	mov	cl,[esi+edx]
	shl	ecx,16
	mov	dl,[ebp+5]
	mov	ch,[esi+edx]
	mov	dl,[ebp+4]
	mov	cl,[esi+edx]
	mov	[eax],ecx
	add	eax,edi
	add	ebp,8
	dec	ebx

	jnz	.loop

.done	pop	edi
	pop	esi
	pop	ebp
	pop	ebx
	ret	4

;************************

	SECTION .text

EXTERN setvlinebpl_
EXTERN setpitch3

GLOBAL	@ASM_PatchPitch@0
GLOBAL	_ASM_PatchPitch
GLOBAL	ASM_PatchPitch

ASM_PatchPitch:
_ASM_PatchPitch:
@ASM_PatchPitch@0:
	mov	eax,[dc_pitch]
	mov	[rdcp1+2],eax
	mov	[rdcp2+2],eax
	mov	[rdcp3+2],eax
	call	setpitch3
	jmp	setvlinebpl_


