;
;	Command & Conquer Red Alert(tm)
;	Copyright 2025 Electronic Arts 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 3 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, see <http://www.gnu.org/licenses/>.
;

;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Command & Conquer                        *
;*                                                                         *
;*                    File Name : KEYFBUFF.ASM                             *
;*                                                                         *
;*                   Programmer : David R. Dettmer                         *
;*                                                                         *
;*                   Start Date : March 3, 1995                            *
;*                                                                         *
;*                  Last Update :                                          *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;*   Buffer_Frame_To_Page -- Copies a linear buffer to a virtual viewport  *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *

;********************** Model & Processor Directives ***********************
IDEAL
P386
MODEL USE32 FLAT


;******************************** Includes *********************************
INCLUDE "gbuffer.inc"


;******************************** Equates **********************************

TRUE	equ	1			; Boolean 'true' value
FALSE	equ	0			; Boolean 'false' value

;*=========================================================================*/
;* The following are defines used to control what functions are linked	   *
;* in for Buffer_Frame_To_Page.						   *
;*=========================================================================*/
;USE_NORMAL		EQU	TRUE
;USE_HORZ_REV 		EQU	TRUE
;USE_VERT_REV 		EQU	TRUE
;USE_SCALING 		EQU	TRUE


FLAG_NORMAL		EQU	0
FLAG_TRANS		EQU	1
FLAG_GHOST		EQU	2
FLAG_FADING		EQU	4
FLAG_PREDATOR		EQU	8

FLAG_MASK		EQU	0Fh


SHAPE_NORMAL 		EQU	0000h		; Standard shape
;SHAPE_HORZ_REV 		EQU	0001h		; Flipped horizontally
;SHAPE_VERT_REV 		EQU	0002h		; Flipped vertically
;SHAPE_SCALING 		EQU	0004h		; Scaled (WORD scale_x, WORD scale_y)
;SHAPE_VIEWPORT_REL 	EQU	0010h		; Coords are window-relative
;SHAPE_WIN_REL 		EQU	0010h		; Coordinates are window relative instead of absolute.
SHAPE_CENTER 		EQU	0020h		; Coords are based on shape's center pt
SHAPE_TRANS		EQU	0040h		; has transparency

SHAPE_FADING 		EQU	0100h		; Fading effect (VOID * fading_table,
						;   WORD fading_num)
SHAPE_PREDATOR 		EQU	0200h		; Transparent warping effect
;SHAPE_COMPACT 		EQU	0400h		; Never use this bit
;SHAPE_PRIORITY 		EQU	0800h		; Use priority system when drawing
SHAPE_GHOST		EQU	1000h		; Shape is drawn ghosted
;SHAPE_SHADOW		EQU	2000h
SHAPE_PARTIAL  		EQU	4000h
;SHAPE_COLOR 		EQU	8000h		; Remap the shape's colors
						;   (VOID * color_table)


;
;.......................... Shadow Effect ..................................
;
SHADOW_COL		EQU	00FFh	; magic number for shadows

;......................... Priority System .................................
;
CLEAR_UNUSED_BITS  	EQU	0007h	; and with 0000-0111 to clear
					;  non-walkable high bit and
					;  scaling id bits
NON_WALKABLE_BIT  	EQU	0080h	; and with 1000-0000 to clear all
					;  but non-walkable bit
;
;......................... Predator Effect .................................
;
;PRED_MASK		EQU	0007h	; mask used for predator pixel puts
PRED_MASK		EQU	000Eh	; mask used for predator pixel puts


;---------------------------------------------------------------------------
;
; Use a macro to make code a little cleaner.
; The parameter varname is optional.
; Syntax to use macro is :
;  WANT equ expression
;  USE func [,varname]
; If the 'varname' is defined, a table declaration is created like:
;	GLOBAL	TableName:DWORD
; Then, the table entry is created:
;  If WANT is true, the table entry is created for the given function:
;	varname	DD	func
;  If WANT is not TRUE, a Not_Supported entry is put in the table:
;	varname	DD	Not_Supported
; The resulting tables look like:
;
;	GLOBAL	ExampTable:DWORD
;	ExampTable	DD	routine1
;			DD	routine2
;			DD	routine3
;			...
; Thus, each table is an array of function pointers.
;
;---------------------------------------------------------------------------
MACRO USE func, varname
 IF WANT
  varname 	DD	func
 ELSE
  varname	DD	Not_Supported
 ENDIF
ENDM

; IFNB <varname>
;	GLOBAL	varname:DWORD
; ENDIF

;---------------------------------------------------------------------------


DATASEG

;---------------------------------------------------------------------------
; Predator effect variables
;---------------------------------------------------------------------------
; make table for negative offset and use the used space for other variables

BFPredNegTable	DW	-1, -3, -2, -5, -2, -4, -3, -1
	; 8 words below calculated
		DW	0, 0, 0, 0, 0, 0, 0, 0	; index ffffff00
		DD	0, 0, 0, 0		; index ffffff10
BFPredOffset	DD	0, 0, 0, 0		; index ffffff20
		DD	0, 0, 0, 0		; index ffffff30
	; partially faded predator effect value
BFPartialPred	DD	0, 0, 0, 0		; index ffffff40
BFPartialCount	DD	0, 0, 0, 0		; index ffffff50
		DD	0, 0, 0, 0		; index ffffff60
		DD	0, 0, 0, 0		; index ffffff70
		DD	0, 0, 0, 0		; index ffffff80
		DD	0, 0, 0, 0		; index ffffff90
		DD	0, 0, 0, 0		; index ffffffa0
		DD	0, 0, 0, 0		; index ffffffb0
		DD	0, 0, 0, 0		; index ffffffc0
		DD	0, 0, 0, 0		; index ffffffd0
		DD	0, 0, 0, 0		; index ffffffe0
		DD	0, 0, 0, 0		; index fffffff0
BFPredTable	DW	1, 3, 2, 5, 2, 3, 4, 1
;BFPredTable	DB	1, 3, 2, 5, 4, 3, 2, 1


CODESEG

;---------------------------------------------------------------------------
; Code Segment Tables:
; This code uses the USE macro to set up tables of function addresses.
; The tables have the following format:
; Tables defined are:
;	BufferFrameTable
;---------------------------------------------------------------------------

WANT	equ 	<TRUE>
USE	BF_Copy, BufferFrameTable

WANT	equ 	<TRUE>
USE	BF_Trans

WANT	equ 	<TRUE>
USE	BF_Ghost

WANT	equ 	<TRUE>
USE	BF_Ghost_Trans

WANT	equ 	<TRUE>
USE	BF_Fading

WANT	equ 	<TRUE>
USE	BF_Fading_Trans

WANT	equ 	<TRUE>
USE	BF_Ghost_Fading

WANT	equ 	<TRUE>
USE	BF_Ghost_Fading_Trans

WANT	equ 	<TRUE>
USE	BF_Predator

WANT	equ 	<TRUE>
USE	BF_Predator_Trans

WANT	equ 	<TRUE>
USE	BF_Predator_Ghost

WANT	equ 	<TRUE>
USE	BF_Predator_Ghost_Trans

WANT	equ 	<TRUE>
USE	BF_Predator_Fading

WANT	equ 	<TRUE>
USE	BF_Predator_Fading_Trans

WANT	equ 	<TRUE>
USE	BF_Predator_Ghost_Fading

WANT	equ 	<TRUE>
USE	BF_Predator_Ghost_Fading_Trans

;---------------------------------------------------------------------------

global _Int3:near
proc _Int3 near
	int	3
	ret
endp


;***************************************************************************
;* VVC::TOPAGE -- Copies a linear buffer to a virtual viewport		   *
;*                                                                         *
;* INPUT:	WORD	x_pixel		- x pixel on viewport to copy from *
;*		WORD	y_pixel 	- y pixel on viewport to copy from *
;*		WORD	pixel_width	- the width of copy region	   *
;*		WORD	pixel_height	- the height of copy region	   *
;*		BYTE *	src		- buffer to copy from		   *
;*		VVPC *  dest		- virtual viewport to copy to	   *
;*                                                                         *
;* OUTPUT:      none                                                       *
;*                                                                         *
;* WARNINGS:    Coordinates and dimensions will be adjusted if they exceed *
;*	        the boundaries.  In the event that no adjustment is 	   *
;*	        possible this routine will abort.  If the size of the 	   *
;*		region to copy exceeds the size passed in for the buffer   *
;*		the routine will automatically abort.			   *
;*									   *
;* HISTORY:                                                                *
;*   06/15/1994 PWG : Created.                                             *
;*=========================================================================*
	GLOBAL	C Buffer_Frame_To_Page:NEAR
	PROC	Buffer_Frame_To_Page C near
	USES	eax,ebx,ecx,edx,esi,edi

	;*===================================================================
	;* define the arguements that our function takes.
	;*===================================================================
	ARG	x_pixel     :DWORD		; x pixel position in source
	ARG	y_pixel     :DWORD		; y pixel position in source
	ARG	pixel_width :DWORD		; width of rectangle to blit
	ARG	pixel_height:DWORD		; height of rectangle to blit
	ARG    	src         :DWORD		; this is a member function
	ARG	dest        :DWORD		; what are we blitting to

	ARG	flags       :DWORD		; flags passed

	;*===================================================================
	; Define some locals so that we can handle things quickly
	;*===================================================================
	LOCAL	IsTranslucent		:DWORD	; ptr to the is_translucent table
	LOCAL	Translucent		:DWORD	; ptr to the actual translucent table
	LOCAL	FadingTable		:DWORD	; extracted fading table pointer
	LOCAL	FadingNum		:DWORD	; get the number of times to fade

	LOCAL	StashECX		:DWORD	; temp variable for ECX register

	LOCAL	jflags			:DWORD	; flags used to goto correct buff frame routine
	LOCAL	BufferFrameRout		:DWORD	; ptr to the buffer frame routine

	LOCAL	jmp_loc			:DWORD	; calculated jump location
	LOCAL	loop_cnt		:DWORD

	LOCAL 	x1_pixel		:DWORD
	LOCAL	y1_pixel		:DWORD
	LOCAL	scr_x			:DWORD
	LOCAL	scr_y			:DWORD
	LOCAL	dest_adjust_width	:DWORD
	LOCAL	scr_adjust_width	:DWORD


	cmp	[ src ] , 0
	jz	??real_out

	;====================================================================
	; Pull off optional arguments:
	; EDI is used as an offset from the 'flags' parameter, to point
	; to the optional argument currently being processed.
	;====================================================================
??do_args:
	mov	edi , 4	 			; optional params start past flags
	mov	[ jflags ] , 0			; clear jump flags

??check_centering:
	;-------------------------------------------------------------------
	; See if we need to center the frame
	;-------------------------------------------------------------------
	test	[ flags ] , SHAPE_CENTER	; does this need to be centered?
	je	??check_trans			; if not the skip over this stuff

	mov	eax , [ pixel_width ]
	mov	ebx , [ pixel_height ]
	sar	eax , 1
	sar	ebx , 1
	sub	[ x_pixel ] , eax
	sub	[ y_pixel ] , ebx

??check_trans:
	test	[ flags ] , SHAPE_TRANS
	jz	??check_ghost

	or	[ jflags ] , FLAG_TRANS

	;--------------------------------------------------------------------
	; SHAPE_GHOST: DWORD is_translucent tbl
	;--------------------------------------------------------------------
??check_ghost:
	test	[ flags ] , SHAPE_GHOST		; are we ghosting this shape
	jz	??check_fading

	mov	eax , [ flags + edi ]
	or	[ jflags ] , FLAG_GHOST
	mov	[ IsTranslucent ] , eax		; save ptr to is_trans. tbl
	add	eax , 0100h			; add 256 for first table
	add	edi , 4				; next argument
	mov	[ Translucent ] , eax		; save ptr to translucent tbl

	;--------------------------------------------------------------------
	; SHAPE_FADING: DWORD fade_table[256], DWORD fade_count
	;--------------------------------------------------------------------
??check_fading:
	test	[ flags ] , SHAPE_FADING	; are we fading this shape
	jz	??check_predator

	mov	eax , [ flags + edi ]
	mov	[ FadingTable ] , eax		; save address of fading tbl
	mov	eax , [ flags + edi + 4 ]	; get fade num
	or	[ jflags ] , FLAG_FADING
	and	eax , 03fh			; no need for more than 63
	add	edi , 8				; next argument
	cmp	eax , 0				; check if it's 0
	jnz	??set_fading			; if not, store fade num

	and	[ flags ] , NOT SHAPE_FADING	; otherwise, don't fade

??set_fading:
	mov	[ FadingNum ] , eax

	;--------------------------------------------------------------------
	; SHAPE_PREDATOR: DWORD init_pred_lookup_offset (0-7)
	;--------------------------------------------------------------------
??check_predator:
	test	[ flags ] , SHAPE_PREDATOR	; is predator effect on
	jz	??check_partial

	mov	eax , [ flags + edi ]		; pull the partial value
	or	[ jflags ] , FLAG_PREDATOR
	shl	eax , 1
	cmp	eax , 0
	jge	??check_range

	neg	eax
	mov	ebx , -1
	and	eax , PRED_MASK			; keep entries within bounds
	mov	bl , al
	mov	eax , ebx			; will be ffffff00-ffffff07
	jmp	??pred_cont

??check_range:
	and	eax , PRED_MASK			; keep entries within bounds

??pred_cont:
	add	edi , 4				; next argument
	mov	[ BFPredOffset ] , eax
	mov	[ BFPartialCount ] , 0		; clear the partial count
	mov	[ BFPartialPred ] , 100h	; init partial to off

??pred_neg_init:
	mov  	esi , [ dest ]	    ; get ptr to dest
	mov	ebx, 7 * 2

??pred_loop:
	movzx	eax , [ WORD PTR BFPredNegTable + ebx ]
	add	eax , [ (GraphicViewPort esi) . GVPWidth ]	; add width
	add	eax , [ (GraphicViewPort esi) . GVPXAdd ]	; add x add
	mov	[ WORD PTR BFPredNegTable + 16 + ebx ] , ax
	dec	ebx
	dec	ebx
	jge	??pred_loop

	;--------------------------------------------------------------------
	; SHAPE_PARTIAL: DWORD partial_pred_value (0-255)
	;--------------------------------------------------------------------
??check_partial:
	test	[ flags ] , SHAPE_PARTIAL		; is this a partial pred?
	jz	??setupfunc

	mov	eax , [ flags + edi ]		; pull the partial value
	add	edi , 4				; next argument
	and	eax , 0ffh			; make sure 0-255
	mov	[ BFPartialPred ] , eax		; store it off

??setupfunc:
	mov	ebx , [ jflags ]		; load flags value
	and	ebx , FLAG_MASK			; clip high bits
	add	ebx , ebx			; mult by 4 to get DWORD offset
	add	ebx , ebx
	mov	ebx , [ BufferFrameTable + ebx ]	; get table value
	mov	[ BufferFrameRout ] , ebx		; store it in the function pointer

; Clip dest Rectangle against source Window boundaries.

	mov	[ scr_x ] , 0
	mov	[ scr_y ] , 0
	mov  	esi , [ dest ]	    ; get ptr to dest
	xor 	ecx , ecx
	xor 	edx , edx
	mov	edi , [ (GraphicViewPort esi) . GVPWidth ]  ; get width into register
	mov	ebx , [ x_pixel ]
	mov	eax , [ x_pixel ]
	add	ebx , [ pixel_width ]
	shld	ecx , eax , 1
	mov	[ x1_pixel ] , ebx
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	mov	edi,[ ( GraphicViewPort esi) . GVPHeight ] ; get height into register
	mov	ebx , [ y_pixel ]
	mov	eax , [ y_pixel ]
	add	ebx , [ pixel_height ]
	shld	ecx , eax , 1
	mov	[ y1_pixel ] , ebx
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	xor	cl , 5
	xor	dl , 5
	mov	al , cl
	test	dl , cl
	jnz	??real_out

	or	al , dl
	jz	??do_blit

	test	cl , 1000b
	jz	??dest_left_ok

	mov	eax , [ x_pixel ]
	neg	eax
	mov	[ x_pixel ] , 0
	mov	[ scr_x ] , eax

??dest_left_ok:
	test	cl , 0010b
	jz	??dest_bottom_ok

	mov	eax , [ y_pixel ]
	neg	eax
	mov	[ y_pixel ] , 0
	mov	[ scr_y ] , eax

??dest_bottom_ok:
	test	dl , 0100b
	jz	??dest_right_ok

	mov	eax , [ (GraphicViewPort esi) . GVPWidth ]  ; get width into register
	mov	[ x1_pixel ] , eax

??dest_right_ok:
	test	dl , 0001b
	jz	??do_blit

	mov	eax , [ (GraphicViewPort esi) . GVPHeight ]  ; get width into register
	mov	[ y1_pixel ] , eax

??do_blit:
	cld
	mov	eax , [ (GraphicViewPort esi) . GVPXAdd ]
	add	eax , [ (GraphicViewPort esi) . GVPWidth ]
	mov	edi , [ (GraphicViewPort esi) . GVPOffset ]

	mov	ecx , eax
	mul	[ y_pixel ]
	add	edi , [ x_pixel ]
	add	edi , eax

	add	ecx , [ x_pixel ]
	sub	ecx , [ x1_pixel ]
	mov	[ dest_adjust_width ] , ecx

	mov	esi , [ src ]
	mov	eax , [ pixel_width ]
	sub	eax , [ x1_pixel ]
	add	eax , [ x_pixel ]
	mov	[ scr_adjust_width ] , eax

	mov	eax , [ scr_y ]
	mul	[ pixel_width ]
	add	eax , [ scr_x ]
	add	esi , eax

	mov	edx , [ y1_pixel ]
	mov	eax , [ x1_pixel ]

	sub	edx , [ y_pixel ]
	jle	??real_out

	sub	eax , [ x_pixel ]
	jle	??real_out

	jmp	[ BufferFrameRout ]	; buffer frame to viewport routine

??real_out:
	ret


; ********************************************************************
; Forward bitblit only
; the inner loop is so efficient that
; the optimal consept no longer apply because
; the optimal byte have to by a number greather than 9 bytes
; ********************************************************************

BF_Copy:

	cmp	eax , 10
	jl	??forward_loop_bytes

??forward_loop_dword:
	mov	ecx , edi
	mov	ebx , eax
	neg	ecx
	and	ecx , 3
	sub	ebx , ecx
	rep	movsb
	mov	ecx , ebx
	shr	ecx , 2
	rep	movsd
	mov	ecx , ebx
	and	ecx , 3
	rep	movsb
	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??forward_loop_dword

	ret

??forward_loop_bytes:
	mov	ecx , eax
	rep	movsb
	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx					; decrement the height
	jnz	??forward_loop_bytes

	ret


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

BF_Trans:

; calc the code location to skip to 10 bytes per REPT below!!!!
	mov	ecx , eax
	and	ecx , 01fh
	lea	ecx , [ ecx + ecx * 4 ]		; quick multiply by 5
	neg	ecx
	shr	eax , 5
	lea	ecx , [ ??trans_reference + ecx * 2 ] ; next multiply by 2
	mov	[ loop_cnt ] , eax
	mov	[ jmp_loc ] , ecx

??trans_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

; the following code should NOT be changed without changing the calculation
; above!!!!!!

??trans_line:

	REPT	32
	local	trans_pixel
		mov	bl , [ esi ]
		inc	esi
		test	bl , bl
		jz	trans_pixel

		mov	[ edi ] , bl

	trans_pixel:
		inc	edi
	ENDM

??trans_reference:
	dec	ecx
	jge	??trans_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??trans_loop

	ret


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

BF_Ghost:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??ghost_reference - ??ghost_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??ghost_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??ghost_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??ghost_line:

	REPT	32
	local	store_pixel
		mov	al , [ esi ]
		inc	esi
		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	store_pixel

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al

	store_pixel:
		mov	[ edi ] , al
		inc	edi

	ENDM

??ghost_reference:
	dec	ecx
	jge	??ghost_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??ghost_loop

	ret


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

BF_Ghost_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??ghost_t_reference - ??ghost_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??ghost_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??ghost_t_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??ghost_t_line:

	REPT	32
	local	transp_pixel
	local	store_pixel
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	transp_pixel

		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	store_pixel

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al

	store_pixel:
		mov	[ edi ] , al

	transp_pixel:
		inc	edi

	ENDM

??ghost_t_reference:
	dec	ecx
	jge	??ghost_t_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??ghost_t_loop

	ret


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

BF_Fading:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??fading_reference - ??fading_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??fading_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??fading_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	mov	ebx , [ FadingTable ]		; run color through fading table
	jmp	[ jmp_loc ]

??fading_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??fading_line:

	REPT	32
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

		mov	[ edi ] , al
		inc	edi

	ENDM

??fading_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??fading_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??fading_loop

	ret


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

BF_Fading_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??fading_t_reference - ??fading_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??fading_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??fading_t_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	mov	ebx , [ FadingTable ]		; run color through fading table
	jmp	[ jmp_loc ]

??fading_t_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??fading_t_line:

	REPT	32
	local	transp_pixel
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	transp_pixel

		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

		mov	[ edi ] , al

	transp_pixel:
		inc	edi

	ENDM

??fading_t_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??fading_t_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??fading_t_loop

	ret


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

BF_Ghost_Fading:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??ghost_f_reference - ??ghost_f_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??ghost_f_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??ghost_f_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??ghost_f_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??ghost_f_line:

	REPT	32
	local	store_pixel
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		mov	ebx , [ IsTranslucent ]		; is it a lucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	do_fading

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the lation table
							; ((_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (_color * 256) of the lation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
; DRD		jmp	store_pixel

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

	store_pixel:
		mov	[ edi ] , al
		inc	edi

	ENDM

??ghost_f_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??ghost_f_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??ghost_f_loop

	ret


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

BF_Ghost_Fading_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??ghost_f_t_reference - ??ghost_f_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??ghost_f_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??ghost_f_t_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??ghost_f_t_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??ghost_f_t_line:

	REPT	32
	local	transp_pixel
	local	store_pixel
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	transp_pixel

		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	do_fading

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
; DRD		jmp	store_pixel

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

	store_pixel:
		mov	[ edi ] , al

	transp_pixel:
		inc	edi

	ENDM

??ghost_f_t_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??ghost_f_t_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??ghost_f_t_loop

	ret


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

BF_Predator:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_reference - ??predator_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??predator_line:

	REPT	32
	local	get_pred
	local	skip_pixel
		mov	al , [ esi ]
		inc	esi
		mov	ebx , [ BFPartialCount ]
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	skip_pixel

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

;		xor	bh , bh
;		mov	eax , [ BFPredValue ]	; pick up a color offset a pseudo-
;						;  random amount from the current
;		mov	[ BFPartialCount ] , ebx
;		mov	al , [ edi + eax ]	;  viewport address

		mov	[ edi ] , al

	skip_pixel:
		inc	edi

	ENDM

??predator_reference:
	dec	ecx
	jge	??predator_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_loop

	ret


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

BF_Predator_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_t_reference - ??predator_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_t_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??predator_t_line:

	REPT	32
	local	trans_pixel
	local	get_pred
	local	store_pixel
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	trans_pixel

		mov	ebx , [ BFPartialCount ]
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	store_pixel

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	store_pixel:
		mov	[ edi ] , al

	trans_pixel:
		inc	edi

	ENDM

??predator_t_reference:
	dec	ecx
	jge	??predator_t_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_t_loop

	ret


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

BF_Predator_Ghost:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_g_reference - ??predator_g_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_g_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_g_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??predator_g_line:

	REPT	32
	local	get_pred
	local	check_ghost
	local	store_pixel
		mov	al , [ esi ]
		mov	ebx , [ BFPartialCount ]
		inc	esi
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	check_ghost

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	check_ghost:
		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	store_pixel

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al

	store_pixel:
		mov	[ edi ] , al
		inc	edi

	ENDM

??predator_g_reference:
	dec	ecx
	jge	??predator_g_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_g_loop

	ret


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

BF_Predator_Ghost_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_g_t_reference - ??predator_g_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_g_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_g_t_loop:
	mov	ecx , [ loop_cnt ]
	jmp	[ jmp_loc ]

??predator_g_t_line:

	REPT	32
	local	trans_pixel
	local	get_pred
	local	check_ghost
	local	store_pixel
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	trans_pixel

		mov	ebx , [ BFPartialCount ]
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	check_ghost

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	check_ghost:
		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	store_pixel

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al

	store_pixel:
		mov	[ edi ] , al

	trans_pixel:
		inc	edi

	ENDM

??predator_g_t_reference:
	dec	ecx
	jge	??predator_g_t_line

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_g_t_loop

	ret


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

BF_Predator_Fading:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_f_reference - ??predator_f_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_f_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_f_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??predator_f_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??predator_f_line:

	REPT	32
	local	get_pred
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		mov	ebx , [ BFPartialCount ]
		inc	esi
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	do_fading

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

		mov	[ edi ] , al
		inc	edi

	ENDM

??predator_f_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??predator_f_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_f_loop

	ret


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

BF_Predator_Fading_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_f_t_reference - ??predator_f_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_f_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_f_t_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??predator_f_t_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??predator_f_t_line:

	REPT	32
	local	trans_pixel
	local	get_pred
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	trans_pixel

		mov	ebx , [ BFPartialCount ]
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	do_fading

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

		mov	[ edi ] , al

	trans_pixel:
		inc	edi

	ENDM

??predator_f_t_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??predator_f_t_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_f_t_loop

	ret


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

BF_Predator_Ghost_Fading:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_g_f_reference - ??predator_g_f_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_g_f_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_g_f_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??predator_g_f_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??predator_g_f_line:

	REPT	32
	local	get_pred
	local	check_ghost
	local	store_pixel
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		mov	ebx , [ BFPartialCount ]
		inc	esi
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	check_ghost

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	check_ghost:
		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	do_fading

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
; DRD		jmp	store_pixel

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

	store_pixel:
		mov	[ edi ] , al
		inc	edi

	ENDM

??predator_g_f_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??predator_g_f_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_g_f_loop

	ret


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

BF_Predator_Ghost_Fading_Trans:

	mov	ebx , eax			; width

	; NOTE: the below calculation assumes a group of instructions is
	;	less than 256 bytes

	; get length of the 32 groups of instructions

	lea	ecx , [ ??predator_g_f_t_reference - ??predator_g_f_t_line ]

	shr	ebx , 5				; width / 32
	shr	ecx , 5				; length of instructions / 32
	and	eax , 01fh			; mod of width / 32
	mul	cl				; calc offset to start of group
	neg	eax				; inverse of width
	mov	[ loop_cnt ] , ebx		; save width / 32
	lea	ecx , [ ??predator_g_f_t_reference + eax ]
	mov	eax , 0
	mov	[ jmp_loc ] , ecx

??predator_g_f_t_loop:
	mov	ecx , [ loop_cnt ]
	mov	[ StashECX ] , ecx		; preserve ecx for later
	jmp	[ jmp_loc ]

??predator_g_f_t_line_begin:
	mov	[ StashECX ] , ecx		; preserve ecx for later

??predator_g_f_t_line:

	REPT	32
	local	trans_pixel
	local	get_pred
	local	check_ghost
	local	store_pixel
	local	do_fading
	local	fade_loop
		mov	al , [ esi ]
		inc	esi
		test	al , al
		jz	trans_pixel

		mov	ebx , [ BFPartialCount ]
		add	ebx , [ BFPartialPred ]
		or	bh , bh
		jnz	get_pred		; is this a predator pixel?

		mov	[ BFPartialCount ] , ebx
		jmp	check_ghost

	get_pred:
		xor	bh , bh
		mov	eax, [ BFPredOffset ]
		mov	[ BFPartialCount ] , ebx
		add	[ BYTE PTR BFPredOffset ] , 2
		movzx	eax , [ WORD PTR BFPredTable + eax ]
		and	[ BYTE PTR BFPredOffset ] , PRED_MASK
						; pick up a color offset a pseudo-
						;  random amount from the current
		movzx	eax , [ BYTE PTR edi + eax ]	;  viewport address

	check_ghost:
		mov	ebx , [ IsTranslucent ]		; is it a translucent color?
		mov	bh , [ BYTE PTR ebx + eax ]
		cmp	bh , 0ffh
		je	do_fading

		and	ebx , 0FF00h			; clear all of ebx except bh
							; we have the index to the translation table
							; ((trans_colour * 256) + dest colour)
		mov	al , [ edi ]			; mov pixel at destination to al
		add	ebx , [ Translucent ]		; get the ptr to it!
							; Add the (trans_color * 256) of the translation equ.
		mov	al , [ BYTE PTR ebx + eax ]	; get new pixel in al
; DRD		jmp	store_pixel

	do_fading:
		mov	ebx , [ FadingTable ]		; run color through fading table
		mov	ecx , [ FadingNum ]

	fade_loop:
		mov	al, [BYTE PTR ebx + eax]
		dec	ecx
		jnz	fade_loop

	store_pixel:
		mov	[ edi ] , al

	trans_pixel:
		inc	edi

	ENDM

??predator_g_f_t_reference:
	mov	ecx , [ StashECX ]		; restore ecx for main draw loop
	dec	ecx
	jge	??predator_g_f_t_line_begin

	add	esi , [ scr_adjust_width ]
	add	edi , [ dest_adjust_width ]
	dec	edx
	jnz	??predator_g_f_t_loop

	ret


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

Not_Supported:
	ret

	ENDP	Buffer_Frame_To_Page
END

;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Westwood Library                         *
;*                                                                         *
;*                    File Name : KEYFBUFF.ASM                             *
;*                                                                         *
;*                   Programmer : Phil W. Gorrow                           *
;*                                                                         *
;*                   Start Date : July 16, 1992                            *
;*                                                                         *
;*                  Last Update : October 2, 1994   [JLB]                  *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;*   BUFFER_FRAME_TO_LOGICPAGE --                                          *
;*   Normal_Draw -- Function that writes a normal pixel line               *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *

	IDEAL
	P386
IDEAL_MODE	EQU	1
	INCLUDE "wwlib.i"

	;-------------------------------------------------------------------
	; Extern all the library variables that this module requires
	;-------------------------------------------------------------------

	EXTRN	C MaskPage:WORD
	EXTRN	C BackGroundPage:WORD

	;-------------------------------------------------------------------
	; Define all the equates that this module requires
	;-------------------------------------------------------------------

WIN_X		EQU	0		; offset for the x coordinate
WIN_Y		EQU	2		; offset for the y coordinate
WIN_WIDTH	EQU	4		; offset for the window width
WIN_HEIGHT	EQU	6		; offset for the window height
BYTESPERROW	EQU	320		; number of bytes per row

FLAG_NORMAL		EQU	0		; flag for normal draw

FLAG_GHOST		EQU	1		; This flag enables the ghost
FLAG_PRIORITY_TRANS	EQU	2		; flag for priority and transparent
FLAG_TRANS		EQU	4		; flag for transparent draw
FLAG_PRIORITY		EQU	8		; flag for priority draw

						; fx on the above flags

FLAG_MASK		EQU	15		; used to and of uneeded bits

SHAPE_NORMAL		EQU	0000h		; Standard shape.
;SHAPE_HORZ_REV		EQU	0001h		; Flipped horizontally.
;SHAPE_VERT_REV		EQU	0002h		; Flipped vertically.
;SHAPE_SCALING		EQU	0004h		; Scaled (WORD scale_x, WORD scale_y)

SHAPE_WIN_REL		EQU	0010h		; Coordinates are window relative instead of absolute.
SHAPE_CENTER		EQU	0020h		; Coordinates are based on shape's center point.
SHAPE_TRANS		EQU	0040h		; has transparency


;SHAPE_FADING		EQU	0100h		; Fading effect active (VOID * fading_table, WORD fading_num).
;SHAPE_PREDATOR		EQU	0200h		; Transparent warping effect.
;SHAPE_COMPACT		EQU	0400h		; Never use this bit.
SHAPE_PRIORITY		EQU	0800h		; Use priority system when drawing.

SHAPE_GHOST		EQU	1000h		; Transluscent table process.
;SHAPE_SHADOW		EQU	2000h		; ????
;SHAPE_PARTIAL 		EQU	4000h		; ????
;SHAPE_COLOR		EQU	8000h		; Remap the shape's colors (VOID * color_table).


; MBL MOD 12.1.92

CLEAR_NON_WALK_BIT_AND_SCALE_BITS	EQU	7	; Makes it one AND per pixel in Priority_Trans display
CLEAR_NON_WALK_BIT    	EQU	7fh	; and with 0111-1111 to clear non-walkable high bit
CLEAR_SCALE_BITS  	EQU	87h	; and with 1000-0111 to clear scaling id bits
NON_WALKABLE_BIT  	EQU	80h	; and with 1000-0000 to clear all but non-walkable bit

; END MBL MOD


	CODESEG

	;   1 = GHOST (all odd entrys are prefixed with Ghost_)
	;   2 = BLAAAH
	;   4 = Trans (prfx)
	;   8 = Prior (prfx)


;---------------------------------------------------------------------------
; Define the table of different line draw types
;---------------------------------------------------------------------------

LineTable	DW	WSA_Normal_Draw			;0
		DW	Ghost_Normal_Draw		;1
		DW	0				;2
		DW	0				;3

		DW	Transparent_Draw		;4
		DW	Ghost_Transparent_Draw		;5
		DW	0				;6
		DW	0				;7

		DW	Priority_Draw			;8
		DW	Ghost_Priority_Draw		;9
		DW	0				;10
		DW	0				;11

		DW	Priority_Transparent_Draw	;12
		DW	Ghost_Priority_Transparent_Draw	;13
		DW	0				;14
		DW	0				;15



;***************************************************************************
;* BUFFER_FRAME_TO_LOGICPAGE --                                            *
;*                                                                         *
;*                                                                         *
;*                                                                         *
;* INPUT:                                                                  *
;*                                                                         *
;* OUTPUT:                                                                 *
;*                                                                         *
;* WARNINGS:                                                               *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/16/1992 PWG : Created.                                             *
;*=========================================================================*
	PUBLIC	C Buffer_Frame_To_LogicPage
	PROC	C Buffer_Frame_To_LogicPage FAR USES ax bx ecx dx ds esi es edi

	;-------------------------------------------------------------------
	; Define the arguements that our program takes.
	;-------------------------------------------------------------------

	ARG	x_pixel:WORD		; x pixel position to draw at
	ARG	y_pixel:WORD		; y pixel position to draw at
	ARG	pixel_w:WORD		; pixel width of draw region
	ARG	pixel_h:WORD		; pixel height of draw region
	ARG	win:WORD		; window to clip around
	ARG	flags:WORD		; flags that this routine will take
	ARG	buffer:DWORD		; pointer to the buffer with data
	ARG	args:WORD

	;-------------------------------------------------------------------
	; Define the local variables that our program uses
	;-------------------------------------------------------------------

	LOCAL	IsTranslucent:DWORD	; ptr to the is_translucent table
	LOCAL	Translucent:DWORD	; ptr to the actual translucent table

	LOCAL	win_x1:WORD		; clip window left x pixel position
	LOCAL	win_x2:WORD		; clip window right x pixel position
	LOCAL	win_y1:WORD		; clip window top y pixel position
	LOCAL	win_y2:WORD		; clip window bottom y pixel position
	LOCAL	clipleft:WORD		; number of pixels to clip on left
	LOCAL	clipright:WORD		; number of pixels to clip on right
	LOCAL	nextline:WORD		; offset to the next line
	LOCAL	putmiddle:WORD 		; routine to call to put the middle
	LOCAL	maskpage:WORD		; location of the depth masks
	LOCAL   background:WORD		; location of the background data
	LOCAL   jflags:WORD		; location of the background data

	LOCAL	priority:BYTE		; the priority level of the back

	push	fs

	xor	ecx,ecx

	;--------------------------------------------------------------------
	; Check to see if we have supplied any GHOST tables.
	;--------------------------------------------------------------------
	push	di

	mov	di,6
	mov	[jflags],0

??ghost:
	test	[flags],SHAPE_GHOST	; are we ghosting this shape
	jz	short ??no_ghost	; if not then skip and do more

	or	[jflags],FLAG_GHOST

	les	ax,[DWORD PTR buffer + di]

	; get the "are we really translucent?" table
	mov	[WORD PTR IsTranslucent],ax
	mov	[WORD PTR IsTranslucent + 2],es
	add	ax,0100h		; add to offset for tables

	; get the "ok we are translucent!!" table
	mov	[WORD PTR Translucent],ax
	mov	[WORD PTR Translucent + 2],es

	add	di,4

??no_ghost:

	pop	di

	;-------------------------------------------------------------------
	; See if we need to center the frame
	;-------------------------------------------------------------------
	test	[flags],SHAPE_CENTER	; does this need to be centered?
	je	short ??no_centering	; if not the skip over this stuff

	mov	ax,[pixel_w]
	mov	bx,[pixel_h]
	sar	ax,1
	sar	bx,1
	sub	[x_pixel],ax
	sub	[y_pixel],bx

??no_centering:
	mov	ax,[flags]
	and	ax,SHAPE_PRIORITY+SHAPE_TRANS
	cmp	ax,SHAPE_PRIORITY+SHAPE_TRANS
	jne	short ??test_trans

	or	[jflags],FLAG_PRIORITY_TRANS
	jmp	short ??priority

	;-------------------------------------------------------------------
	; Get the trans information if we need to get it
	;-------------------------------------------------------------------
??test_trans:
	test	[flags],SHAPE_TRANS	; does this draw use transparencies?
	je	short ??test_priority	; if not the skip over this junk

	or	[jflags],FLAG_TRANS

??test_priority:
	;-------------------------------------------------------------------
	; Get the priority information if we need to get it
	;-------------------------------------------------------------------
	test	[flags],SHAPE_PRIORITY	; does this draw use priorities?
	je	short ??no_priority	; if not the skip over this junk

	or	[jflags],FLAG_PRIORITY

??priority:
	mov	ax,[BackGroundPage]	; get the background page from ds
	mov	[background],ax		;    and store it on the stack
	mov	ax,[MaskPage]		; get the mask page from ds
	mov	[maskpage],ax		;    and store it on the stack
	mov	ax,[WORD PTR buffer + 4]; get the priority level from args
	mov	[priority],al		;    and store it in a local

	;-------------------------------------------------------------------
	; Get the draw routine that we are going to draw with
	;-------------------------------------------------------------------
??no_priority:
;	mov	bx,[flags]		; load in the current flags byte
;	and	bx,FLAG_MASK		; prevent lockup on bad value
	mov	bx,[jflags]		; load in the jump table flags
	shl	bx,1
	mov	ax,[WORD PTR LineTable + bx]	; get the offset of the skip table
	mov	[putmiddle],ax		; store off the new offset

	;-------------------------------------------------------------------
	; Get a pointer to the logic page to where we will draw our buffer
	;-------------------------------------------------------------------
	push	[LogicPage]		; push the current logic page
	call	FAR PTR Get_Page	; get the physical page address
	add	sp,2			; pull the parameter from the stack
	mov	es,dx			; store the address in the dest

	;--------------------------------------------------------------------
	; Point DI to the beginning of the window that we need to look at.
	;   that way we can access all of the info through di.
	;--------------------------------------------------------------------
	mov	si,OFFSET WindowList	; get the offset of the window list
	mov	cl,4			; shift 3 times = multiply by 16
	mov	ax,[win]		; get the window number we are using
	shl	ax,cl			; each window is 8 words long
	add	si,ax			; add that into the offset of window

	;--------------------------------------------------------------------
	; Place all the clipping values on the stack so our function will
	; be truly re-entrant and will not need to shadow these values.
	;--------------------------------------------------------------------
	mov	cl,3			; to convert x to pixel mult by 8
	mov	ax,[si + WIN_X]		; get the left clip position
	shl	ax,cl			; convert to a pixel x position
	mov	[win_x1],ax		; store the left edge of window
	mov	[win_x2],ax

	mov	ax,[si + WIN_WIDTH]	; get the width of the window
	shl	ax,cl			; convert to a pixel width
	add	[win_x2],ax		; add to get the right window edge

	mov	ax,[si + WIN_Y]		; get the win y coordinate to clip
	mov	[win_y1],ax		; and save it onto the stack

	add	ax,[si + WIN_HEIGHT]	; calculate the bottom win y coord
	mov	[win_y2],ax		; and save it onto the stack

	test	[flags],SHAPE_WIN_REL	; is this window relative?
	je	short ??get_buffer	; if not the skip over

	mov	ax,[win_x1]		; get left edge of window
	add	[x_pixel],ax		; add to x pixel position
	mov	ax,[win_y1]		; get top edge of window
	add	[y_pixel],ax		; add to y pixel position

	;--------------------------------------------------------------------
	; Get a pointer to the source buffer so we can handle the clipping
	;--------------------------------------------------------------------
??get_buffer:
	lds	si,[buffer]		; get a pointer to the buffer

	;--------------------------------------------------------------------
	; Check the top of our shape and clip any lines that are necessary
	;--------------------------------------------------------------------
	mov	ax,[y_pixel]		; get the y_pixel draw position
	sub	ax,[win_y1]		; subtract out the window y top
	jns	short ??check_bottom		;   skip if y below window top
	add	ax,[pixel_h]		; add in the height of the region
	jg	short ??clip_top		; if positive then clip top lines

??jump_exit:
	jmp	??exit			; otherwise completely clipped

??clip_top:
	xchg	[pixel_h],ax
	sub	ax,[pixel_h]
	add	[y_pixel],ax
	mul	[pixel_w]		; convert to number of bytes to skip
	add	si,ax			; skip past the necessary bytes

	;--------------------------------------------------------------------
	; Check the bottom of our shape and clip it if necessary
	;--------------------------------------------------------------------
??check_bottom:
	mov	ax,[win_y2]		; get the bottom y of the window
	sub	ax,[y_pixel]		; subtract of the y to draw at
	js	??jump_exit		; if its signed then nothing to draw
	jz	??jump_exit		; if its zero then nothing to draw

	cmp	ax,[pixel_h]		; if more room to draw then height
	jae	short ??clip_x_left		;   then go check the left clip
	mov	[pixel_h],ax		; clip all but amount that will fit

??clip_x_left:
	mov	[clipleft],0		; clear clip on left of region
	mov	ax,[x_pixel]		; get the pixel x of draw region
	sub	ax,[win_x1]		; pull out the window coordinate
	jns	short ??clip_x_right
	neg	ax			; negate to get amnt to skip in buf
	mov	[clipleft],ax		; store it in the left clip info
	add	[x_pixel],ax		; move to the edge of the window
	sub	[pixel_w],ax		; pull it out of the pixel width

??clip_x_right:
	mov	[clipright],0		; clear clip on right of region
	mov	ax,[win_x2]		; get the window x of clip region
	sub	ax,[x_pixel]		; subtract the draw edge of region
	js	??jump_exit		; if its negative then get out
	jz	??jump_exit		; if its zero then get out

	cmp	ax,[pixel_w]		; is space available larger than w
	jae	short ??draw_prep		;   if so then go get drawing


	xchg	[pixel_w],ax		; amt to draw in pixel_w (wid in ax)
	sub	ax,[pixel_w]		; pull out the amount to draw
	mov	[clipright],ax		; this is the amount to clip on right

??draw_prep:
	push	si			; save off source pos in buffer
	push	ds			;   both offset and segment
	mov	ax,@data
	mov	ds,ax
	mov	bx,[y_pixel]
	shl	bx,1			; shift left by 1 for word table look
	lds	si,[YTable]	; get the address of the ytable
	mov	di,[ds:si+bx]		; look up the multiplied value
	pop	ds			; restore source pos in buffer
	pop	si			;   both offset and segment

	add	di,[x_pixel]		; add in the x pixel position
	mov	[nextline],di		; save it off in the next line

 	;--------------------------------------------------------------------
	; Now determine the type of the shape and process it in the proper
	;   way.
	;--------------------------------------------------------------------
	mov	dx,[pixel_h]

	; Check to see if the WSA is the screen width and there is no
	; clipping. In this case, then a special single call to the
	; line processing routine is possible.
	mov	ax,[clipleft]
	add	ax,[clipright]
	jne	short ??top_of_loop
	cmp	[pixel_w],BYTESPERROW
	jne	short ??top_of_loop

	;------------------------------------
	; The width of the WSA is the screen width, so just process as
	; one large WSA line.
	mov	ax,BYTESPERROW
	imul	dx
	mov	cx,ax
	call	[putmiddle]
	jmp	short ??exit

	;------------------------------------
	; Process line by line.
??top_of_loop:
	add	si,[clipleft]		; skip whats necessary on left edge
	mov	cx,[pixel_w]		; get the width we need to draw

	; Copy the source to the destination as appropriate. This routine can
	; trash AX, BX, CX, and DI. It must properly modify SI to point one byte past
	; the end of the data.
	call	[putmiddle]

	add	si,[clipright]		; skip past the left clip
	add	[nextline],BYTESPERROW
	mov	di,[nextline]

	dec	dx
	jnz	??top_of_loop

??exit:
	pop	fs
	ret
	ENDP


;***************************************************************************
;* NORMAL_DRAW -- Function that writes a normal pixel line                 *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*=========================================================================*

	PROC	NOLANGUAGE WSA_Normal_Draw NEAR

 IF 1
 	; This version is marginally faster than the later version.
 	mov	ax,cx
	shr	cx,2
	rep movsd
	and	ax,011b
	mov	cx,ax
	shr	cx,1
	rep movsw
	adc	cx,cx
	rep movsb
	ret

 ELSE

	shr	cx,1			; convert to words (odd pix in carry)
	rep	movsw			; write out the needed words
	adc	cx,0			; add the carry into cx
	rep	movsb			; write out the odd byte if any
	ret
 ENDIF

	ENDP


;***************************************************************************
;* TRANSPARENT_DRAW -- Function that writes a transparent pixel line       *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*   10/02/1994 JLB : Optimized for 250% speed improvement.                *
;*=========================================================================*
	PROC	NOLANGUAGE Transparent_Draw NEAR

 IF 1
	; Preserve DX since it is used as a scratch register.
	push	dx

??loop:
	; Swap DS:SI and ES:DI back in preparation for the REP SCASB
	; instruction.
	xchg	di,si
	mov	dx,es
	mov	ax,ds
	mov	ds,dx
	mov	es,ax

	; Remember the bytes remaining in order to calculate the position
	; of the scan when it stops.
	mov	bx,cx

	; Scan looking for a non-zero value in the source buffer.
	xor	al,al
	repe scasb

	; When the loop ends, if the EQ flag is set then the scanning is
	; complete. Jump to the end of the routine in order to fixup the
	; pointers.
	je	short ??fini

	; Advance the destination pointer by the amount necessary to match
	; the source movement. DS:SI points to where data should be written.
	add	si,bx
	inc	cx		; SCASB leaves CX one too low, fix it.
	dec	di		; SCASB leaves DI one byte too far, fix it.
	sub	si,cx

	; Scan for the duration of non-zero pixels. This yields a count which
	; is used to copy the source data to the destination. Preserve DI.
	mov	dx,di
	mov	bx,cx
	repne scasb
	mov	di,dx

	; Set BX to equal the number of bytes to copy from source to dest.
	inc	cx		; SCASB leaves CX one too low, fix it.
	sub	bx,cx

	; Move the data from ES:DI to DS:SI for BX bytes.
	xchg	cx,bx		; Make CX=bytes to move, BX=bytes remaining.

	; Swap DS:SI and ES:DI in preparation for the REP MOV instruction.
	xchg	di,si
	mov	dx,es
	mov	ax,ds
	mov	ds,dx
	mov	es,ax

	; Move the data from source to dest. First try to move double
	; words. Then copy the remainder bytes (if any). Putting jumps in
	; this section doesn't result in any savings -- oh well.
	mov	ax,cx
	shr	cx,2
	rep movsd
	and	ax,0011b
	mov	cx,ax
	shr	cx,1
	rep movsw
	adc	cx,cx
	rep movsb

	; Restore CX with the remaining bytes to process.
	mov	cx,bx

	; If there are more bytes to process, then loop back.
	or	cx,cx
	jne	short ??loop

??fini:
	; Swap ES:DI and DS:SI back to original orientation.
	mov	ax,ds
	mov	bx,es
	mov	es,ax
	mov	ds,bx
	xchg	di,si

	; Restore DX and return.
	pop	dx
	ret

 ELSE

??loop_top:
	lodsb
	or	al,al
	jz	short ??skip

	mov	[es:di],al		; store the pixel to the screen
??skip:
	inc	di
	loop	??loop_top
	ret

 ENDIF

	ENDP


;***************************************************************************
;* PRIORITY_DRAW -- Function that writes a pixels if they are in front of  *
;*		    the given plate.					   *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
;*   17/01/1993 MCC : Updated for 386, and optimized			   *
;*=========================================================================*

	PROC	NOLANGUAGE Priority_Draw NEAR

	mov	fs,[background]		; get the SEG of the background page
	mov	gs,[maskpage]		; get the SEG of the mask info
	mov	ah,[priority]		; keep a copy of priority varible for faster cmp


??loop_top:
	lodsb				; get the pixel to draw on the screen

					; get the mask byte for our pixel
	mov	bl,[ds:di]
					; get rid of non-walkable bit and
					; get rid of scaling id bits
	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS

	cmp	ah,bl			; are we more toward the front?
	jge	short ??out_pixel	; if so then write the pixel

	mov	al,[fs:di]		; get the pixel to write
??out_pixel:
	stosb				; write the pixel and inc the DI
	loop	??loop_top
	ret

	ENDP


;***************************************************************************
;* PRIORITY_TRANSPARENT_DRAW -- Function that writes a pixels if they are  *
;*		    in front of the given plate.  It also deals with	   *
;*		    transparent pixels.					   *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
;*   17/01/1993 MCC : Updated for 386, and optimized			   *
;*=========================================================================*

	PROC	NOLANGUAGE Priority_Transparent_Draw NEAR

	mov	fs,[background]		; get the SEG of the background page
	mov	gs,[maskpage]		; get the SEG of the mask info
	mov	ah,[priority]		; keep a copy of priority varible for faster cmp

??loop_top:
	lodsb				; get the pixel on the screen
	or	al,al			; check to see if al is transparent
	je	short ??write_back	; if it is go write background

	mov	bl,[gs:di]		; get the mask byte for our pixel

					; get rid of non-walkable bit and
					; get rid of scaling id bits
	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS

	cmp	ah,bl			; are we more toward the front?
	jge	short ??out_pixel	; if so then write the pixel

??write_back:
	mov	al,[fs:di]		; get the pixel to write
??out_pixel:
	stosb				; write the pixel
	loop	??loop_top
	ret

	ENDP


;***************************************************************************
;* GHOST_NORMAL_DRAW -- Function that writes a normal pixel line           *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   05/27/1993 MCC : Created.                                             *
;*=========================================================================*

	PROC	NOLANGUAGE Ghost_Normal_Draw NEAR

??loop_top:
	lodsb

;---
	; Ok, find out if the colour is a Translucent colour
	push	ax
	push 	ds

	lds	bx,[IsTranslucent]
	mov	ah,al			; preserve real pixel
	xlat				; get new al (transluecent pixel
	xchg	ah,al			; get real pixel back into AL just in case
	cmp	ah,255
	je	short ??normal_pixel		; is it a translucent ?
					; if we get passed here value in
					; AH should be 0-15

	; yes, it is a translucent colour so goto our translucent translation
	; table and set up a ptr to the correct table

	mov	al,[es:di]
					; mov pixel at destination to al and we have
					; the index to the translation table
					; ((trans_colour * 256) + dest colour)
	lds	bx,[Translucent]	; get the ptr to it!
	add	bh,ah			; Add the (trans_color * 256) of the translation equ.
					; XLAT only uses AL so no need to clear AH
	xlat				; get new pixel in AL

??normal_pixel:
	pop	ds
	pop	bx
	mov	ah,bh
;---

	mov	[es:di],al		; store the pixel to the screen

??skip:
	inc	di
	loop	??loop_top

	ret

	ENDP


;***************************************************************************
;* GHOST_TRANSPARENT_DRAW -- Function that writes a transparent pixel line *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   05/27/1993 MCC : Created.                                             *
;*=========================================================================*
	PROC	NOLANGUAGE Ghost_Transparent_Draw NEAR

??loop_top:
	lodsb
	or	al,al
	jz	short ??skip

;---
	; Ok, find out if the colour is a Translucent colour
	push	ax
	push 	ds

	lds	bx,[IsTranslucent]
	mov	ah,al			; preserve real pixel
	xlat				; get new al (transluecent pixel
	xchg	ah,al			; get real pixel back into AL just in case
	cmp	ah,255
	je	short ??normal_pixel		; is it a translucent ?
					; if we get passed here value in
					; AH should be 0-15

	; yes, it is a translucent colour so goto our translucent translation
	; table and set up a ptr to the correct table

	mov	al,[es:di]
					; mov pixel at destination to al and we have
					; the index to the translation table
					; ((trans_colour * 256) + dest colour)
	lds	bx,[Translucent]	; get the ptr to it!
	add	bh,ah			; Add the (trans_color * 256) of the translation equ.
					; XLAT only uses AL so no need to clear AH
	xlat				; get new pixel in AL

??normal_pixel:
	pop	ds
	pop	bx
	mov	ah,bh
;---

	mov	[es:di],al		; store the pixel to the screen

??skip:
	inc	di
	loop	??loop_top
	ret

	ENDP


;***************************************************************************
;* GHOST_PRIORITY_DRAW -- Function that writes a pixels if they are in fron*
;*		    the given plate.					   *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
;*   05/27/1993 MCC : Updated to use the new Ghosting fx		   *
;*   17/01/1993 MCC : Updated for 386, and optimized			   *
;*=========================================================================*
	PROC	NOLANGUAGE Ghost_Priority_Draw NEAR

	mov	fs,[background]		; get the SEG of the background page
	mov	gs,[maskpage]		; get the SEG of the mask info
	mov	ah,[priority]		; keep a copy of priority varible for faster cmp


??loop_top:
	lodsb				; get the pixel to draw on the screen
					; get the mask byte for our pixel
	mov	bl,[ds:di]
					; get rid of non-walkable bit and
					; get rid of scaling id bits
	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
	cmp	ah,bl			; are we more toward the front?
	jge	short ??out_pixel	; if so then write the pixel

	mov	al,[fs:di]		; get the pixel to write
??out_pixel:
	stosb				; write the pixel and inc the DI
	loop	??loop_top

	ret

	ENDP


;***************************************************************************
;* GHOST_PRIORITY_TRANSPARENT_DRAW -- Function that writes a pixels if they*
;*		    in front of the given plate.  It also deals with	   *
;*		    transparent pixels.					   *
;*                                                                         *
;* INPUT:	cx    - number of pixels to write                          *
;*		ds:si - buffer which holds the pixels to write		   *
;*		es:di - place to put the pixels we are writing		   *
;*                                                                         *
;* OUTPUT:      ds:si - points to next pixel past last pixel read          *
;*		es:di - points to next pixel past last pixel written	   *
;*                                                                         *
;* WARNINGS:    none                                                       *
;*                                                                         *
;* HISTORY:                                                                *
;*   07/17/1992 PWG : Created.                                             *
;*   12/01/1992 MBL : Updated to work with latest mask data encoding.      *
;*   05/27/1993 MCC : Updated to use the new Ghosting fx		   *
;*   17/01/1993 MCC : Updated for 386, and optimized			   *
;*=========================================================================*
	PROC	NOLANGUAGE Ghost_Priority_Transparent_Draw NEAR

	mov	fs,[background]		; get the SEG of the background page
	mov	gs,[maskpage]		; get the SEG of the mask info
	mov	ah,[priority]		; keep a copy of priority varible for faster cmp

??loop_top:
	lodsb				; get the pixel on the screen
	or	al,al			; check to see if al is transparent
	je	short ??write_back	;   if it is go write background
	mov	bl,[gs:di]		; get the mask byte for our pixel
					; get rid of non-walkable bit and
					; get rid of scaling id bits
	and	bl,CLEAR_NON_WALK_BIT_AND_SCALE_BITS
	cmp	ah,bl			; are we more toward the front?
	jge	short ??out_pixel	; if so then write the pixel
??write_back:
	mov	al,[fs:di]		; get the pixel to write
??out_pixel:
	stosb				; write the pixel
	loop	??loop_top

	ret

	ENDP

	END
