	IDEAL
	MODEL	MEDIUM,C
	P286

SCREENSEG	=	0a000h

FINEANGLES	=	3600
DEG90		=	900
DEG180		=	1800
DEG270		=	2700
DEG360		=	3600

OP_JLE		=	07eh
OP_JGE		=	07dh

EXTRN	finetangent:DWORD	; far array, starts at offset 0

EXTRN	HitHorizWall:FAR
EXTRN	HitVertWall:FAR
EXTRN	HitHorizDoor:FAR
EXTRN	HitVertDoor:FAR
EXTRN	HitHorizPWall:FAR
EXTRN	HitVertPWall:FAR


DATASEG

EXTRN	viewwidth:WORD

EXTRN	tilemap:BYTE
EXTRN	spotvis:BYTE
EXTRN	pixelangle:WORD


EXTRN	midangle:WORD
EXTRN	angle:WORD

EXTRN	focaltx:WORD
EXTRN	focalty:WORD
EXTRN	viewtx:WORD
EXTRN	viewty:WORD
EXTRN	viewx:DWORD
EXTRN	viewy:DWORD

EXTRN	xpartialup:WORD
EXTRN	ypartialup:WORD
EXTRN	xpartialdown:WORD
EXTRN	ypartialdown:WORD

EXTRN	tilehit:WORD
EXTRN	pixx:WORD
EXTRN	wallheight:WORD			; array of VIEWWIDTH entries

EXTRN	xtile:WORD
EXTRN	ytile:WORD
EXTRN	xtilestep:WORD
EXTRN	ytilestep:WORD
EXTRN	xintercept:DWORD
EXTRN	yintercept:DWORD
EXTRN	xstep:DWORD
EXTRN	ystep:DWORD

EXTRN	doorposition:WORD		; table of door position values


EXTRN	pwallpos:WORD			; amound a pushable wall has been moved

CODESEG

;-------------------
;
; xpartialbyystep
;
; multiplies long [ystep] (possibly negative), by word [xpartial] (in BX)
;
; returns dx:ax
; trashes bx,cx,di
;
;-------------------

PROC xpartialbyystep NEAR
;
; setup
;
	mov	ax,[WORD ystep]
	mov	cx,[WORD ystep+2]
	or	cx,cx               ; is ystep negatice?
	jns	@@multpos
;
; multiply negative cx:ax by bx
;
	neg	cx
	neg	ax
	sbb	cx,0

	mul	bx					; fraction*fraction
	mov	di,dx				; di is low word of result
	mov	ax,cx				;
	mul	bx					; units*fraction
	add	ax,di
	adc	dx,0

	neg	dx
	neg	ax
	sbb	dx,0
	ret
;
; multiply positive cx:ax by bx
;
EVEN
@@multpos:
	mul	bx					; fraction*fraction
	mov	di,dx				; di is low word of result
	mov	ax,cx				;
	mul	bx					; units*fraction
	add	ax,di
	adc	dx,0

	ret

ENDP



;-------------------
;
; ypartialbyxstep
;
; multiplies long [xstep] (possibly negative), by word [ypartial] (in BP)
;
; returns dx:ax
; trashes cx,di,bp
;
;-------------------

PROC ypartialbyxstep NEAR
;
; setup
;
	mov	ax,[WORD xstep]
	mov	cx,[WORD xstep+2]
	or	cx,cx               ; is ystep negatice?
	jns	@@multpos
;
; multiply negative cx:ax by bx
;
	neg	cx
	neg	ax
	sbb	cx,0

	mul	bp					; fraction*fraction
	mov	di,dx				; di is low word of result
	mov	ax,cx				;
	mul	bp					; units*fraction
	add	ax,di
	adc	dx,0

	neg	dx
	neg	ax
	sbb	dx,0
	ret
;
; multiply positive cx:ax by bx
;
EVEN
@@multpos:
	mul	bp					; fraction*fraction
	mov	di,dx				; di is low word of result
	mov	ax,cx				;
	mul	bp					; units*fraction
	add	ax,di
	adc	dx,0
	ret

ENDP


;============================
;
; AsmRefresh
;
;
;============================

PROC	AsmRefresh
PUBLIC	AsmRefresh

	push	si
	push	di
	push	bp

	mov	[pixx],0
;---------------------------------------------------------------------------
;
; Setup to trace a ray through pixx view pixel
;
; CX : angle of the ray through pixx
; ES : points to segment of finetangent array for this block of code
;
; Upon entrance to initialize block
;
; BX : xpartial
; BP : ypartial
;
;---------------------------------------------------------------------------
	EVEN
pixxloop:
	mov	ax,SEG finetangent
	mov	es,ax
	mov	cx,[midangle]			; center of view area
	mov	bx,[pixx]
	shl	bx,1
	add	cx,[pixelangle+bx]		; delta for this pixel
	cmp	cx,0
	jge	not0
;----------
;
; -90 - -1 degree arc
;
;----------
	add	cx,FINEANGLES			; -90 is the same as 270
	jmp	entry360

not0:
	cmp	cx,DEG90
	jge	not90
;----------
;
; 0-89 degree arc
;
;----------
entry90:
	mov	[xtilestep],1			; xtilestep = 1
	mov	[ytilestep],-1			; ytilestep = -1
	mov	[BYTE cs:horizop],OP_JGE	; patch a jge in
	mov	[BYTE cs:vertop],OP_JLE		; patch a jle in
	mov	bx,DEG90-1
	sub	bx,cx
	shl	bx,2
	mov	ax,[es:bx]
	mov	dx,[es:bx+2]
	mov	[WORD xstep],ax
	mov	[WORD xstep+2],dx		; xstep = finetangent[DEG90-1-angle]
	mov	bx,cx
	shl	bx,2
	mov	ax,[es:bx]
	mov	dx,[es:bx+2]
	neg	dx
	neg	ax
	sbb	dx,0
	mov	[WORD ystep],ax
	mov	[WORD ystep+2],dx		; ystep = -finetangent[angle]

	mov	bx,[xpartialup]			; xpartial = xpartialup
	mov	bp,[ypartialdown]		; ypartial = ypartialdown
	jmp	initvars

not90:
	cmp	cx,DEG180
	jge	not180
;----------
;
; 90-179 degree arc
;
;----------
	mov	ax,-1
	mov	[xtilestep],ax			; xtilestep = -1
	mov	[ytilestep],ax			; ytilestep = -1
	mov	[BYTE cs:horizop],OP_JLE	; patch a jle in
	mov	[BYTE cs:vertop],OP_JLE		; patch a jle in

	mov	bx,cx
	shl	bx,2
	mov	ax,[es:bx-DEG90*4]
	mov	dx,[es:bx+2-DEG90*4]
	neg	dx
	neg	ax
	sbb	dx,0
	mov	[WORD xstep],ax
	mov	[WORD xstep+2],dx		; xstep = -finetangent[angle-DEG90]
	mov	bx,DEG180-1
	sub	bx,cx
	shl	bx,2
	mov	ax,[es:bx]
	mov	dx,[es:bx+2]
	neg	dx
	neg	ax
	sbb	dx,0
	mov	[WORD ystep],ax
	mov	[WORD ystep+2],dx		; ystep = -finetangent[DEG180-1-angle]

	mov	bx,[xpartialdown]		; xpartial = xpartialdown
	mov	bp,[ypartialdown]		; ypartial = ypartialdown
	jmp	initvars

not180:
	cmp	cx,DEG270
	jge	not270
;----------
;
; 180-269 degree arc
;
;----------
	mov	[xtilestep],-1			; xtilestep = -1
	mov	[ytilestep],1			; ytilestep = 1
	mov	[BYTE cs:horizop],OP_JLE	; patch a jle in
	mov	[BYTE cs:vertop],OP_JGE		; patch a jge in

	mov	bx,DEG270-1
	sub	bx,cx
	shl	bx,2
	mov	ax,[es:bx]
	mov	dx,[es:bx+2]
	neg	dx
	neg	ax
	sbb	dx,0
	mov	[WORD xstep],ax
	mov	[WORD xstep+2],dx		; xstep = -finetangent[DEG270-1-angle]
	mov	bx,cx
	shl	bx,2
	mov	ax,[es:bx-DEG180*4]
	mov	dx,[es:bx+2-DEG180*4]
	mov	[WORD ystep],ax
	mov	[WORD ystep+2],dx		; ystep = finetangent[angle-DEG180]

	mov	bx,[xpartialdown]		; xpartial = xpartialdown
	mov	bp,[ypartialup]			; ypartial = ypartialup
	jmp	initvars


not270:
	cmp	cx,DEG360
	jge	not360
;----------
;
; 270-359 degree arc
;
;----------
entry360:
	mov	ax,1
	mov	[xtilestep],ax			; xtilestep = 1
	mov	[ytilestep],ax			; ytilestep = 1
	mov	[BYTE cs:horizop],OP_JGE	; patch a jge in
	mov	[BYTE cs:vertop],OP_JGE		; patch a jge in

	mov	bx,cx
	shl	bx,2
	mov	ax,[es:bx-DEG270*4]
	mov	dx,[es:bx+2-DEG270*4]
	mov	[WORD xstep],ax
	mov	[WORD xstep+2],dx		; xstep = finetangent[angle-DEG270]
	mov	bx,DEG360-1
	sub	bx,cx
	shl	bx,2
	mov	ax,[es:bx]
	mov	dx,[es:bx+2]
	mov	[WORD ystep],ax
	mov	[WORD ystep+2],dx		; ystep = finetangent[DEG360-1-angle]

	mov	bx,[xpartialup]			; xpartial = xpartialup
	mov	bp,[ypartialup]			; ypartial = ypartialup
	jmp	initvars


not360:
;----------
;
; 360-449 degree arc
;
;----------
	sub	cx,FINEANGLES			; -449 is the same as 89
	jmp	entry90

;---------------------------------------------------------------------------
;
; initialise variables for intersection testing
;
;---------------------------------------------------------------------------
initvars:
	call	NEAR xpartialbyystep	; xpartial is in BX
	add	ax,[WORD viewy]
	adc	dx,[WORD viewy+2]
	mov	[WORD yintercept],ax
	mov	[WORD yintercept+2],dx

	mov	si,[focaltx]
	add	si,[xtilestep]
	mov	[xtile],si					; xtile = focaltx+xtilestep
	shl	si,6
	add	si,dx						; xspot = (xtile<<6) + yinttile


	call	NEAR ypartialbyxstep	; ypartial is in BP
	add	ax,[WORD viewx]
	adc	dx,[WORD viewx+2]
	mov	[WORD xintercept],ax
	mov	cx,dx

	mov	bx,[focalty]
	add	bx,[ytilestep]
	mov	bp,bx						; ytile = focalty+ytilestep
	mov	di,dx
	shl	di,6
	add	di,bx						; yspot = (xinttile<<6) + ytile

	mov	bx,[xtile]
	mov	dx,[WORD yintercept+2]
	mov	ax,SCREENSEG
	mov	es,ax						; faster than mov es,[screenseg]


;---------------------------------------------------------------------------
;
; trace along this angle until we hit a wall
;
; CORE LOOP!
;
; All variables are killed when a wall is hit
;
; AX : scratch
; BX : xtile
; CX : high word of xintercept
; DX : high word of yintercept
; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis)
; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis)
; BP : ytile
; ES : screenseg
;
;---------------------------------------------------------------------------

;-----------
;
; check intersections with vertical walls
;
;-----------

	EVEN
vertcheck:
	cmp	dx,bp
vertop:								; 0x7e = jle (ytilestep==-1)
	jle	horizentry					; 0x7d = jge (ytilestep==1)
vertentry:
	test [BYTE tilemap+si],0ffh		; tilehit = *((byte *)tilemap+xspot);
	jnz	hitvert
passvert:
	mov	[BYTE spotvis+si],1			; *((byte *)spotvis+xspot) = true;
	add	bx,[xtilestep]				; xtile+=xtilestep
	mov	ax,[WORD ystep]
	add	[WORD yintercept],ax		; yintercept += ystep
	adc	dx,[WORD ystep+2]
	mov	si,bx
	shl	si,6
	add	si,dx						; xspot = (xtile<<6)+yinttile
	jmp	vertcheck

	EVEN
hitvert:
	mov	al,[BYTE tilemap+si]		; tilehit = *((byte *)tilemap+xspot);
	mov	[BYTE tilehit],al
	or	al,al						; set flags
	jns	notvertdoor
	jmp	vertdoor
notvertdoor:
	mov	[WORD xintercept],0
	mov	[WORD xintercept+2],bx
	mov	[xtile],bx
	mov	[WORD yintercept+2],dx
	mov	[ytile],dx
	call FAR HitVertWall
	jmp nextpix


;-----------
;
; check intersections with horizontal walls
;
;-----------
	EVEN
horizcheck:
	cmp	cx,bx
horizop:							; 0x7e = jle (xtilestep==-1)
	jle	vertentry					; 0x7d = jge (xtilestep==1)
horizentry:
	test [BYTE tilemap+di],0ffh		; tilehit = *((byte *)tilemap+yspot);
	jnz	hithoriz
passhoriz:
	mov	[BYTE spotvis+di],1			; *((byte *)spotvis+yspot) = true;
	add	bp,[ytilestep]				; ytile+=ytilestep
	mov	ax,[WORD xstep]
	add	[WORD xintercept],ax		; xintercept += xstep
	adc	cx,[WORD xstep+2]
	mov	di,cx
	shl	di,6
	add	di,bp						; yspot = (xinttile<<6)+ytile
	jmp	horizcheck

	EVEN
hithoriz:
	mov	al,[BYTE tilemap+di]		; tilehit = *((byte *)tilemap+yspot);
	mov	[BYTE tilehit],al
	or	al,al						; set flags
	js	horizdoor
	mov	[WORD xintercept+2],cx
	mov	[xtile],cx
	mov	[WORD yintercept],0
	mov	[WORD yintercept+2],bp
	mov	[ytile],bp
	call FAR HitHorizWall
	jmp nextpix

;---------------------------------------------------------------------------
;
; next pixel over
;
;---------------------------------------------------------------------------

nextpix:
	mov	ax,[pixx]
	inc	ax
	mov	[pixx],ax
	cmp	ax,[viewwidth]
	jge	done
	jmp	pixxloop
done:
	pop	bp
	pop	di
	pop	si
	retf

;===========================================================================

;=============
;
; hit a special horizontal wall, so find which coordinate a door would be
; intersected at, and check to see if the door is open past that point
;
;=============
horizdoor:
	mov	[xtile],bx					; save off live register variables
	mov	[WORD yintercept+2],dx

	test al,040h      				; both high bits set == pushable wall
	jnz	horizpushwall

	mov	bx,ax
	and	bx,7fh						; strip high bit
	shl	bx,1                        ; index into word width door table

	mov	ax,[WORD xstep]
	mov	dx,[WORD xstep+2]
	sar	dx,1
	rcr ax,1						; half a step gets to door position

	add	ax,[WORD xintercept]		; add half step to current intercept pos
	adc	dx,cx						; CX hold high word of xintercept

	cmp	cx,dx						; is it still in the same tile?
	je	hithmid
;
; midpoint is outside tile, so it hit the side of the wall before a door
;
continuehoriz:
	mov	bx,[xtile]					; reload register variables
	mov	dx,[WORD yintercept+2]
	jmp	passhoriz					; continue tracing
;
; the trace hit the door plane at pixel position AX, see if the door is
; closed that much
;
; draw the door
;

hithmid:
	cmp     ax,8000h
	jb      horiztrekfirst
	;       ax is in second half of door
	mov     dx,[doorposition+bx]           ; position of leading edge of door
	shr	  dx,1
	add     dx,8000h
	cmp     ax,dx
	jb      continuehoriz
	jmp     horiztrekdraw
horiztrekfirst:
	;       ax is in first half of door
	mov     dx,[doorposition+bx]           ; position of leading edge of door
	shr	  dx,1
	mov     bx,07fffh
	sub     bx,dx
	cmp     ax,bx
	jg      continuehoriz
;
; draw the trek door
;
horiztrekdraw:
	mov	[WORD xintercept],ax		; save pixel intercept position
	mov	[WORD xintercept+2],cx

	mov	[WORD yintercept],8000h		; intercept in middle of tile
	mov	[WORD yintercept+2],bp

	call	FAR HitHorizDoor
	jmp	nextpix

;============
;
; hit a sliding horizontal wall
;
;============

horizpushwall:
	mov	ax,[WORD xstep+2]			; multiply xstep by pwallmove (0-63)
	mul	[pwallpos]
	mov	bx,ax
	mov	ax,[WORD xstep]
	mul	[pwallpos]
	add	dx,bx

	sar	dx,1						; then divide by 64 to accomplish a
	rcr ax,1						; fixed point multiplication
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1

	add	ax,[WORD xintercept]		; add partial step to current intercept
	adc	dx,cx						; CX hold high word of xintercept

	cmp	cx,dx						; is it still in the same tile?
	jne	continuehoriz				; no, it hit the side

;
; draw the pushable wall at the new height
;
	mov	[WORD xintercept],ax		; save pixel intercept position
	mov	[WORD xintercept+2],dx

	mov	[WORD yintercept+2],bp
	mov	[WORD yintercept],0

	call	FAR HitHorizPWall
	jmp	nextpix



;===========================================================================

;=============
;
; hit a special vertical wall, so find which coordinate a door would be
; intersected at, and check to see if the door is open past that point
;
;=============
vertdoor:
	mov	[xtile],bx					; save off live register variables
	mov	[WORD yintercept+2],dx

	test al,040h      				; both high bits set == pushable wall
	jnz	vertpushwall

	mov	bx,ax
	and	bx,7fh						; strip high bit
	shl	bx,1                        ; index into word width doorposition

	mov	ax,[WORD ystep]
	mov	dx,[WORD ystep+2]
	sar	dx,1
	rcr ax,1						; half a step gets to door position

	add	ax,[WORD yintercept]		; add half step to current intercept pos
	adc	dx,[WORD yintercept+2]

	cmp	[WORD yintercept+2],dx		; is it still in the same tile?
	je	hitvmid
;
; midpoint is outside tile, so it hit the side of the wall before a door
;
continuevert:
	mov	bx,[xtile]					; reload register variables
	mov	dx,[WORD yintercept+2]
	jmp	passvert					; continue tracing
;
; the trace hit the door plane at pixel position AX, see if the door is
; closed that much
;
;
; draw the door
;
hitvmid:
		  cmp     ax,08000h
		  jb      verttrekfirst
		  ;       ax is in second half of door
		  mov     dx,[doorposition+bx]           ; position of leading edge of door
		  shr		 dx,1
		  add     dx,08000h
		  cmp     ax,dx
		  jb      continuevert
		  jmp     verttrekdraw
verttrekfirst:
		  ;       ax is in first half of door
		  mov     dx,[doorposition+bx]           ; position of leading edge of door
		  shr		 dx,1
		  mov     bx,07fffh
		  sub     bx,dx
		  cmp     ax,bx
		  jg      continuevert
;
; draw the trek door
;
verttrekdraw:
	mov	[WORD yintercept],ax		; save pixel intercept position
	mov	[WORD xintercept],8000h		; intercept in middle of tile
	mov	ax,[xtile]
	mov	[WORD xintercept+2],ax

	call	FAR HitVertDoor
	jmp	nextpix

;============
;
; hit a sliding vertical wall
;
;============

vertpushwall:
	mov	ax,[WORD ystep+2]			; multiply ystep by pwallmove (0-63)
	mul	[pwallpos]
	mov	bx,ax
	mov	ax,[WORD ystep]
	mul	[pwallpos]
	add	dx,bx

	sar	dx,1						; then divide by 64 to accomplish a
	rcr ax,1						; fixed point multiplication
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1
	sar	dx,1
	rcr ax,1

	add	ax,[WORD yintercept]		; add partial step to current intercept
	adc	dx,[WORD yintercept+2]

	cmp	[WORD yintercept+2],dx		; is it still in the same tile?
	je		drawvertpushw
	jmp	continuevert				; no, it hit the side

;
; draw the pushable wall at the new height
;
drawvertpushw:
	mov	[WORD yintercept],ax		; save pixel intercept position
	mov	[WORD yintercept+2],dx

	mov	bx,[xtile]
	mov	[WORD xintercept+2],bx
	mov	[WORD xintercept],0

	call	FAR HitVertPWall
	jmp	nextpix



ENDP


END


