PAGE 80,132
TITLE - XTASM.ASM - Assembly routines for 3D engine
;;;.286P
;==============================================================================
; COMMAND LINE ASSEMBLY
;	MASM /B63 /Z /D_Mx FILENAME;
;
;  WHERE Mx SPECIFIES MODEL (l OR c) FOR LARGE OR COMPACT MODELS
;==============================================================================
	INCLUDE		ET.EQU
	INCLUDE		ET.MAC

	ANGLE_30    equ	    160
	ANGLE_360   equ	    1920

	extrn	_bMaps:DWORD
	extrn	_oMaps:DWORD
	extrn	_bdfp:DWORD
	extrn	_PageBegin:WORD
	extrn	_InvCosTable:DWORD
	extrn	_InvSinTable:DWORD
	extrn	_LongCosTable:DWORD
	extrn	_DistanceTable:WORD
	extrn	_AdjustTable:DWORD
	extrn	_CenterRow:WORD
	extrn	_MaxDistance:WORD
	extrn	_TopColor:WORD
	extrn	_BottomColor:WORD

	extrn	_ScreenBuffer:DWORD
	extrn	_VidRow:WORD
	extrn	_lowmask:BYTE
	extrn	_Walls:WORD


	extrn	_xRay:NEAR
	extrn	_yRay:NEAR
	extrn	N_LDIV@:FAR


	PUBLIC		_graphinit
	PUBLIC		_usepage
	PUBLIC		_flippage
	PUBLIC		_SetPalette
	PUBLIC		_DrawWalls
	PUBLIC		_DrawOneObject

SC_INDEX equ	03c4h	;Sequence Controller Index
CRTC_INDEX equ	03d4h	;CRT Controller Index
MISC_OUTPUT equ 03c2h	;Miscellaneous Output register
SCREEN_SEG equ	0a000h	;segment of display memory in mode X


_TEXT	segment byte public 'CODE'
DGROUP	group	_DATA,_BSS
	assume	cs:_TEXT,ds:DGROUP
_ViewPage  dw 0 ; The address of the current view page
_WritePage dw 0 ; The address of the current write page
PageTable dw 4 dup (0)	 ; Address of 4 pages
ScreenWidth dw 320/4	 ; The width of the screen
PageSize    dw 320/4*240 ; The size of each page
CRTParms label	word
		  dw	  00d06h  ;vertical total
		  dw	  03e07h  ;overflow (bit 8 of vertical counts)
		  dw	  04109h  ;cell height (2 to double-scan)
		  dw	  0ea10h  ;v sync start
		  dw	  0ac11h  ;v sync end and protect cr0-cr7
		  dw	  0df12h  ;vertical displayed
		  dw	  00014h  ;turn off dword mode
		  dw	  0e715h  ;v blank start
		  dw	  00616h  ;v blank end
		  dw	  0e317h  ;turn on byte mode
CRT_PARM_LENGTH equ	(($-CRTParms)/2)

_TEXT	ends
_DATA	segment word public 'DATA'
; Index/data pairs for CRT Controller registers that differ between
; mode 13h and mode X.
_d@	label	byte
_DATA	ends
_BSS	segment word public 'BSS'
_b@	label	byte
_BSS	ends


public _graphinit
public _ViewPage,_WritePage
public ScreenWidth,PageSize,PageTable


_TEXT	SEGMENT byte public 'CODE'
	ASSUME cs:_TEXT

;==============================================================================
; void graphinit(int width,int psize,int mask)
;   width - width of the screen in bytes/plane (defaults to 320/4 if 0)
;   psize - size of each page in bytes/plane (defaults to 320*200/4 if 0)
;==============================================================================
PBEGIN	 _graphinit
	mov	ax,13h
	int	10h
	ret
_graphinit endp

;==============================================================================
; void SetVGAmode(void);
;==============================================================================
PBEGIN	_SetVGAmode
	push	bp
	mov	ax,13h
	int	10h		; Set 320x200x256
	pop	bp
	ret
_SetVGAmode endp

;==============================================================================
; void usepage(int page)
;==============================================================================
UPnum	equ	[bp+ABASE]

PBEGIN	_usepage
	ret
_usepage endp

;==============================================================================
; void flippage()
;
; NOTE: Some lines have been commented out for test purposes. If you experience
;	flicker when the page flips, un-comment the lines waiting for vertical
;	retrace.
;==============================================================================
PBEGIN	_flippage
	push	ds
	push	si
	push	di
	mov	ax,0A000H
	mov	es,ax
	xor	di,di
	lds	si,DGROUP:_ScreenBuffer
	mov	cx,32000
;	cli
    rep movsw
;	sti
	pop	di
	pop	si
	pop	ds
	ret
_flippage endp


;==============================================================================
; void SetPalette(unsigned char far *PalBuf);
;==============================================================================
SPbuf	equ	[bp+ABASE]

PBEGIN	_SetPalette
	push	bp
	mov	bp,sp
	push	ds
	push	si

	lds	si,dword ptr SPbuf
	mov	cx,256
	xor	bx,bx
	cld
	mov	dx,3C8H
sp010:
	mov	al,bl
	out	dx,al
	inc	dx
	lodsb
	out	dx,al
	lodsb
	out	dx,al
	lodsb
	out	dx,al
	dec	dx
	inc	bx
	loop	sp010

	pop	si
	pop	ds
	pop	bp
	ret
_SetPalette endp

;==============================================================================
; void DrawWalls(void);
;==============================================================================
Y2	equ	[bp-2]
AVLOW	equ	[bp-4]
AVHI	equ	[bp-6]
VCOL	equ	[bp-8]
BOFFLOW equ	[bp-10]
BOFFHI	equ	[bp-12]
sColor	equ	[bp-14]
fColor	equ	[bp-16]

PBEGIN	_DrawWalls
	push	bp
	mov	bp,sp
	sub	sp,18
	push	ds
	push	si
	push	di

	les	di,dword ptr ds:_ScreenBuffer
	mov	cx,16000
	mov	ax,ds:_TopColor
	mov	ah,al
  rep	stosw
	mov	cx,16000
	mov	ax,ds:_BottomColor
	mov	ah,al
  rep	stosw

	xor	ax,ax			;Initial loop/plane counter
	mov	VCOL,ax			;Set beginning video column
	mov	si,offset _Walls	; Point to wall array

	mov	cx,320			;Number of walls to display
drw020:
	push	ds			;save data segment
	push	si			;save wall pointer
	push	cx			;save wall count
	lodsw				;Get bitmap number
	xchg	ax,bx			;use bx as the index
	shl	bx,1
	shl	bx,1			;dword index into bitmap table
	mov	di,word ptr DGROUP:_bMaps[bx]	    ;offset to bitmap
	mov	es,word ptr DGROUP:_bMaps[bx+2]	    ;segment of bitmap
	lodsw				;get bitmap column to display
	mov	cl,6
	shl	ax,cl			;x64 to get correct row
	add	di,ax			;and add to bitmap offset
	lodsw				;get bitmap distance
	shl	ax,1			; Make word index for table lookup
	mov	si,ax			;save distance
	mov	bx,word ptr DGROUP:_DistanceTable[si]  ;get height of bitmap

	mov	cx,word ptr DGROUP:_CenterRow
	mov	ax,bx			; Pick up the height
	shr	ax,1			; Divide by two
	sub	cx,ax			; And subtract from center for Y1

	mov	ax,cx			; Start with Y1
	add	ax,bx			; and add height to it for Y2

	cmp	ax,199			; Don't let Y2 go beyond screen height
	jle	short drw030
	mov	ax,199			; Else force it to screen height
drw030:
	mov	Y2,ax			;save y2
	shl	si,1			; Turn object distance into dword index

	mov	ax,word ptr DGROUP:_AdjustTable[si+2]
	mov	dx,word ptr DGROUP:_AdjustTable[si]

	mov	AVHI,ax			; Get (64 * 65536) / height
	mov	AVLOW,dx
	xchg	si,di			;si now points to bitmap
	mov	ax,es			; Pick up segment to bitmap
	les	di,dword ptr DGROUP:_ScreenBuffer
	add	di,word ptr VCOL
	mov	word ptr BOFFLOW,0	; Initialize the current bitmap offset
	mov	word ptr BOFFHI,0

	cmp	cx,word ptr Y2		; is Y1 > Y2?
	jge	short drw090		; Yes, get on out
	or	cx,cx			; Y1 <= 0?
	jle	drw050			; Yes, no sky color needed

	mov	bx,cx			; determine video row
	shl	bx,1
	add	di,word ptr ds:_VidRow[bx]

drw050:
	mov	ds,ax			;ds:si->bitmap
	mov	bx,319			; Offset to next video row
	mov	dx,AVLOW		; Hold onto lsb of adjustment
	mov	ax,AVHI			; Pick up msb of bitmap adjustment

;------------------------------------------------------------------------------
; Here is where the actual bitmap is transferred to the screen. Better
; optimization could be done by precalculating the adjustment factor instead
; of looping until Y1 >= 0. This has not been tried so I don't know if the
; speed would make it worth it....
;------------------------------------------------------------------------------
drw060:
	or	cx,cx			; Is Y1 still < 0 ?
	jl	short drw070		; Yes, don't start drawing yet

	movsb				;Move bitmap to video
	dec	si
	add	di,bx			;next row of video

drw070:
	add	word ptr BOFFLOW,dx	; Add lsb to current offset
	adc	si,ax			; Use msb to get next bitmap location
	inc	cx			; Next y1
	cmp	cx,word ptr Y2		; Beyond Y2 yet?
	jl	short drw060		; Nope, keep looping

drw090:
	pop	cx			;get wall count
	pop	si			;recover structure pointer
	pop	ds
	add	si,8			;Wall structure size * 4
	inc	word ptr VCOL		;next video column to display at
	dec	cx
	jz	drw100
	jmp	drw020			;next wall to display

drw100:

drwDone:
	mov	dx,3c5H
	mov	al,0FFH			;Enable all planes again
	out	dx,al
	pop	di
	pop	si
	pop	ds
	mov	sp,bp
	pop	bp
	ret
_DrawWalls endp

;==============================================================================
;			  +4	     +6		+8	    +10	       +12
;  void DrawOneObject(int ObjNum,int ObjCol,int ObjDist,int VidCol,int PageNum);
;==============================================================================
PBEGIN	_DrawOneObject
	push	bp
	mov	bp,sp
	sub	sp,20
	push	si
	push	di
	push	ds

	mov	bx,word ptr [bp+8]	; Get the distance to the bitmap
	shl	bx,1			; Make word index for table lookup
	mov	si,bx			; Save index for now
	mov	bx,word ptr DGROUP:_DistanceTable[bx]

dob010:
	mov	cx,100
	mov	ax,bx		    ; Pick up the height
	shr	ax,1		    ; Divide by two
	sub	cx,ax		    ; And subtract from center for Y1

	mov	di,cx		    ; Start with Y1
	add	di,bx		    ; and add height to it for Y2

	cmp	di,199		    ; Don't let Y2 go beyond screen height
	jle	short dob020
	mov	di,199		    ; Else force it to screen height

dob020:
	mov	word ptr [bp-2],di  ;save y2
	shl	si,1		    ; Turn object distance into dword index

	mov	ax,word ptr DGROUP:_AdjustTable[si+2]
	mov	dx,word ptr DGROUP:_AdjustTable[si]

	mov	word ptr [bp-14],ax	; Get (64 * 65536) / height
	mov	word ptr [bp-16],dx

	mov	bx,word ptr [bp+4]	; Bitmap number to display
	shl	bx,1			; dword index
	shl	bx,1			; dword index
	mov	ax,word ptr DGROUP:_oMaps[bx+2]
	mov	dx,word ptr DGROUP:_oMaps[bx]

	mov	bx,word ptr [bp+6]	; Bitmap column to display
	shl	bx,1
	shl	bx,1
	shl	bx,1
	shl	bx,1
	shl	bx,1
	shl	bx,1			; x 64 to get correct bitmap row
	add	dx,bx			; then add to start of bitmap
	mov	word ptr [bp-6],ax
	mov	word ptr [bp-8],dx
	les	di,dword ptr DGROUP:_ScreenBuffer
	add	di,word ptr [bp+10]	; Video column to display at
	mov	word ptr [bp-18],0	; Initialize the current bitmap offset
	mov	word ptr [bp-20],0

	or	cx,cx			; Is Y1 > 0 ?
	jle	short dob030		; Nope, start above video

	mov	ax,320
	imul	cx
	add	di,ax

dob030:
	cmp	cx,word ptr [bp-2]	; is Y1 > Y2?
	jge	short dob090		; Yes, get on out

	mov	bx,320			;Amount to next row of video
	lds	si,dword ptr [bp-8]	;Get image buffer
	mov	dx,word ptr [bp-16]	; Hold onto lsb of adjustment

dob040:
	or	cx,cx			; Is Y1 still < 0 ?
	jl	short dob080		; Yes, don't start drawing yet

	lodsb
	dec	si
	or	al,al			;Transparent color?
	jz	dob050			;Yes, don't write it to video
	mov	byte ptr es:[di],al	;place character in video

dob050:
	add	di,bx			;next row of video

dob080:
	mov	ax,word ptr [bp-14]	; Pick up msb of bitmap adjustment
	add	word ptr [bp-20],dx	;   and add to current offset
	adc	si,ax			; Keep the msb correct
	inc	cx			; Next y1
	cmp	cx,word ptr [bp-2]	; Beyond Y2 yet?
	jl	short dob040		; Nope, keep looping

dob090:
	pop	ds
	pop	di
	pop	si
	mov	sp,bp
	pop	bp
	ret
_DrawOneObject	  endp


_TEXT	ENDS
	END

