4491 lines
160 KiB
NASM
4491 lines
160 KiB
NASM
page ,132
|
|
;-----------------------------Module-Header-----------------------------;
|
|
; Module Name: POINTER.ASM
|
|
;
|
|
; This file contains the pointer shape routines required to draw the
|
|
; pointer shape on the EGA.
|
|
;
|
|
; Copyright (c) 1992 Microsoft Corporation
|
|
;
|
|
; Exported Functions: none
|
|
;
|
|
; Public Functions: xyCreateMasks
|
|
; vDrawPointer
|
|
; vYankPointer
|
|
;
|
|
; General Description:
|
|
;
|
|
; All display drivers must support a "pointer" for the pointing
|
|
; device. The pointer is a small graphics image which is allowed
|
|
; to move around the screen independantly of all other operations
|
|
; to the screen, and is normally bound to the location of the
|
|
; pointing device. The pointer is non-destructive in nature, i.e.
|
|
; the bits underneath the pointer image are not destroyed by the
|
|
; presence of the pointer image.
|
|
;
|
|
; A pointer consists of an AND mask and an XOR mask, which give
|
|
; combinations of 0's, 1's, display, or inverse display.
|
|
;
|
|
; AND XOR | DISPLAY
|
|
; ----------------------
|
|
; 0 0 | 0
|
|
; 0 1 | 1
|
|
; 1 0 | Display
|
|
; 1 1 | Not Display
|
|
;
|
|
; The pointer also has a "hot spot", which is the pixel of the
|
|
; pointer image which is to be aligned with the actual pointing
|
|
; device location.
|
|
;
|
|
;
|
|
; | For a pointer like this, the hot spot
|
|
; | would normally be the *, which would
|
|
; ---*--- be aligned with the pointing device
|
|
; | position
|
|
; |
|
|
;
|
|
; The pointer may be moved to any location on the screen, be
|
|
; restricted to only a section of the screen, or made invisible.
|
|
; Part of the pointer may actually be off the edge of the screen,
|
|
; and in such a case only the visible portion of the pointer
|
|
; image is displayed.
|
|
;
|
|
;
|
|
;
|
|
; Logically, the pointer image isn't part of the physical display
|
|
; surface. When a drawing operation coincides with the pointer
|
|
; image, the result is the same as if the pointer image wasn't
|
|
; there. In reality, if the pointer image is part of the display
|
|
; surface it must be removed from memory before the drawing
|
|
; operation may occur, and redrawn at a later time.
|
|
;
|
|
; This exclusion of the pointer image is the responsibility of
|
|
; the display driver. If the pointer image is part of physical
|
|
; display memory, then all output operations must perform a hit
|
|
; test to determine if the pointer must be removed from display
|
|
; memory, and set a protection rectangle wherein the pointer must
|
|
; not be displayed. The actual pointer image drawing routine
|
|
; must honor this protection rectangle by never drawing the
|
|
; pointer image within its boundary.
|
|
;
|
|
; This code doesn't distinguish between pointers and icons,
|
|
; they both are the same size, 32 x 32, which comes out square.
|
|
;
|
|
; Restrictions:
|
|
;
|
|
; All routines herein assume protection either via cli/sti
|
|
; or a semephore at higher level code.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.386
|
|
|
|
ifndef DOS_PLATFORM
|
|
.model small,c
|
|
else
|
|
ifdef STD_CALL
|
|
.model small,c
|
|
else
|
|
.model small,pascal
|
|
endif; STD_CALL
|
|
endif; DOS_PLATFORM
|
|
|
|
ASSUME DS: FLAT, SS: FLAT, ES: FLAT
|
|
assume FS: NOTHING, GS: NOTHING
|
|
|
|
.xlist
|
|
include stdcall.inc
|
|
include i386\egavga.inc
|
|
include i386\strucs.inc
|
|
.list
|
|
|
|
PUBLIC PTR_ROUND_RIGHT ;Pointer exclusion needs these
|
|
PUBLIC PTR_ROUND_LEFT
|
|
PUBLIC PTR_WIDTH_BITS
|
|
PUBLIC PTR_HEIGHT
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The following values allow us to set rounding for cursor exclusion.
|
|
; These values are applied as an AND mask (for rounding left) and as
|
|
; an OR mask (for rounding right).
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ROUNDING_SIZE EQU 8 ;Round to byte boundaries
|
|
.ERRNZ ROUNDING_SIZE AND 111b ;Must be at least byte boundary
|
|
PTR_ROUND_RIGHT EQU ROUNDING_SIZE-1
|
|
PTR_ROUND_LEFT EQU -ROUNDING_SIZE
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The RECT_DATA structure is used for describing the rectangles
|
|
; which will be manipulated by this code. The fields are:
|
|
;
|
|
; rd_ptbSave This is the (X,Y) origin of the given rectangle in
|
|
; the save area.
|
|
;
|
|
; rd_ptlScreen This is the (X,Y) origin of the given rectangle on
|
|
; the screen.
|
|
;
|
|
; rd_sizb This is the extents of the rectangle.
|
|
;
|
|
; rd_ptbWork This is the (X,Y) origin of the given rectangle in
|
|
; the work area.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ifdef DUPS_ARE_LEGAL
|
|
|
|
RECT_DATA STRUC
|
|
rd_ptbSave DW ((SIZE POINTB)/2) DUP (0)
|
|
rd_ptlScreen DW ((SIZE POINTL)/2) DUP (0)
|
|
rd_sizb DW ((SIZE SIZEB)/2) DUP (0)
|
|
rd_ptbWork DW ((SIZE POINTB)/2) DUP (0)
|
|
RECT_DATA ENDS
|
|
.ERRNZ SIZE POINTB AND 1
|
|
.ERRNZ SIZE POINTL AND 1
|
|
.ERRNZ SIZE SIZEB AND 1
|
|
|
|
else
|
|
|
|
RECT_DATA STRUC
|
|
rd_ptbSave dw 0 ; POINTB
|
|
rd_ptlScreen dd 0,0 ; POINTL
|
|
rd_sizb dw 0 ; SIZEB
|
|
rd_ptbWork dw 0 ; POINTB
|
|
RECT_DATA ENDS
|
|
.ERRNZ (SIZE POINTB) - 2
|
|
.ERRNZ (SIZE POINTL) - 8
|
|
.ERRNZ (SIZE SIZEB) - 2
|
|
|
|
endif
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The POINTER_DATA structure is used for describing the actual pointer's
|
|
; rectangle. It also contains clipping information and control flags.
|
|
; The fields are:
|
|
;
|
|
; pd_rd RECT_DATA structure as defined above
|
|
;
|
|
; pd_fb Flags as follows:
|
|
;
|
|
; PD_VALID 1 The rectangle contains valid data.
|
|
; 0 The rectangle data is invalid.
|
|
;
|
|
; PD_CLIP_BOTTOM 1 Clip the bottom
|
|
; 0 No bottom clipping needed
|
|
;
|
|
; PD_CLIP_TOP 1 Clip the top
|
|
; 0 No top clipping needed
|
|
;
|
|
; PD_CLIP_LEFT 1 Clip the lhs
|
|
; 0 No lhs clipping needed
|
|
;
|
|
; PD_CLIP_RIGHT 1 Clip the rhs
|
|
; 0 No rhs clipping needed
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ifdef DUPS_ARE_LEGAL
|
|
|
|
POINTER_DATA STRUC
|
|
pd_rd DW ((SIZE RECT_DATA)/2) DUP (0)
|
|
pd_fb DB 0
|
|
DB 0
|
|
POINTER_DATA ENDS
|
|
.ERRNZ SIZE RECT_DATA AND 1
|
|
|
|
else
|
|
|
|
POINTER_DATA struc
|
|
pd_rd dw 0,0,0,0,0,0,0 ; RECT_DATA
|
|
pd_fb db 0
|
|
db 0
|
|
POINTER_DATA ends
|
|
.ERRNZ (size POINTER_DATA) - (SIZE RECT_DATA) - 2
|
|
|
|
endif
|
|
|
|
|
|
PD_CLIP_BOTTOM EQU 10000000b
|
|
PD_CLIP_TOP EQU 01000000b
|
|
PD_CLIP_RIGHT EQU 00100000b
|
|
PD_CLIP_LEFT EQU 00010000b
|
|
PD_VALID EQU 00001000b
|
|
; EQU 00000100b
|
|
; EQU 00000010b
|
|
; EQU 00000001b
|
|
|
|
PD_CLIPPED EQU PD_CLIP_BOTTOM OR PD_CLIP_TOP OR PD_CLIP_RIGHT OR PD_CLIP_LEFT
|
|
|
|
|
|
.DATA
|
|
|
|
PUBLIC pdPtr1
|
|
PUBLIC pdPtr2
|
|
PUBLIC rdFlushX
|
|
PUBLIC rdFlushY
|
|
PUBLIC rdOverlap
|
|
PUBLIC rdReadX
|
|
PUBLIC rdReadY
|
|
PUBLIC rdWork
|
|
|
|
|
|
; Offsets of locations in the EGA/VGA's address
|
|
; space used both to determine and save the state of the EGA/VGA.
|
|
;
|
|
; The actual address within the EGA/VGA's Regen RAM is determined
|
|
; at init time, and is based on the number of vertical scans.
|
|
|
|
EXTRN pPtrSave : DWORD ;offset from bitmap start of pointer
|
|
EXTRN pPtrWork : DWORD ; work areas
|
|
|
|
; !!! This temp flag is a hack to know if the pointer is color or
|
|
; !!! mono. Fix it up
|
|
|
|
|
|
flPointer dd 0
|
|
|
|
|
|
|
|
pdPtr1 POINTER_DATA <> ;Old/New pointer's data
|
|
pdPtr2 POINTER_DATA <> ;Old/New pointer's data
|
|
rdFlushX RECT_DATA <> ;Flush from save area to screen
|
|
rdFlushY RECT_DATA <> ;Flush from save area to screen
|
|
rdOverlap RECT_DATA <> ;And from save area to work area
|
|
rdReadX RECT_DATA <> ;Read from screen to save, xor to work
|
|
rdReadY RECT_DATA <> ;Read from screen to save, xor to work
|
|
rdWork RECT_DATA <> ;Xor from work to screen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; siz?Mask contains the width and height of the working portion of
|
|
; the current AND and XOR mask. Use of this allows us to manipulate
|
|
; less memory when parts of the pointer won't alter the screen image.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
sizbMask SIZEB <WORK_WIDTH,PTR_HEIGHT>
|
|
sizlMask SIZEL <WORK_WIDTH,PTR_HEIGHT>
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; sizsMaxDelta is the maximum distance the old and new pointers may
|
|
; be before they are considered disjoint.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
sizlMaxDelta SIZEL <WORK_WIDTH,WORK_HEIGHT>
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ptlBotRightClip is the coordinate where rhs or bottom clipping
|
|
; will first occur. It is basically the screen width - pointer width.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ptlBotRightClip POINTL <0,0>
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; This is the initial origin in the save buffer.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ptbInitOrigin POINTB <0,0>
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ppdOld is the pointer to the old pointer's POINTER_DATA structure
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ppdOld DD offset FLAT:pdPtr1
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ppdNew is the pointer to the new pointer's POINTER_DATA structure
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ppdNew DD offset FLAT:pdPtr2
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; pAndXor is the pointer to which AND/XOR mask is to be used. It is
|
|
; based on the 3 least significant bits of the pointer's X coordinate.
|
|
; pColor is the pointer to which COLOR mask is to be used.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
pAndXor DD -1
|
|
pColor DD -1
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The following are the masks which make up the pointer image. There
|
|
; will be one AND/XOR/COLOR mask pair for each possible alignment. On
|
|
; move_pointers call, all the alignments will be generated to save time.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
public base_and_masks
|
|
public base_xor_masks
|
|
public base_clr_masks
|
|
|
|
base_and_masks label byte
|
|
REPT (MASK_LENGTH * 8)
|
|
DB ?
|
|
ENDM
|
|
|
|
base_xor_masks label byte
|
|
REPT (MASK_LENGTH * 8)
|
|
DB ?
|
|
ENDM
|
|
|
|
base_clr_masks label byte
|
|
REPT (CLR_MASK_LENGTH * 8)
|
|
DB ?
|
|
ENDM
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; pabAndMasks is an array which points to the start of the mask for
|
|
; each X rotation. It is indexed into using the low 3 bits of the
|
|
; pointer's X coordinate.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
pabAndMasks label dword
|
|
DD offset FLAT:base_and_masks+(0*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(1*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(2*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(3*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(4*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(5*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(6*MASK_LENGTH)
|
|
DD offset FLAT:base_and_masks+(7*MASK_LENGTH)
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; pabClrMasks is an array which points to the start of the mask for
|
|
; each X rotation. It is indexed into using the low 3 bits of the
|
|
; pointer's X coordinate.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
pabClrMasks label dword
|
|
DD offset FLAT:base_clr_masks+(0*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(1*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(2*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(3*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(4*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(5*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(6*CLR_MASK_LENGTH)
|
|
DD offset FLAT:base_clr_masks+(7*CLR_MASK_LENGTH)
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The following flags and flag bytes are used to control which
|
|
; rectangles are used for what.
|
|
;
|
|
; fbFlush controls which rectangles are to be copied from the save
|
|
; area to the screen. Valid flags are:
|
|
;
|
|
; FB_OLD_PTR, FB_FLUSH_X, FB_FLUSH_Y
|
|
;
|
|
; FB_OLD_PTR is mutually exclusive of all other flags
|
|
;
|
|
;
|
|
; fbAndRead controls which rectangles are to be ANDed into the work
|
|
; area from the screen or save area, and which rectangles are to be
|
|
; copied from the screen to the save area. Valid flags are:
|
|
;
|
|
; FB_NEW_PTR, FB_OVERLAP, FB_READ_X, FB_READ_Y, FB_WORK_RECT,
|
|
;
|
|
; FB_NEW_PTR and FB_WORK_RECT are mutually exclusive of all other
|
|
; flags. Note that FB_OVERLAP doesn't apply when coping into the
|
|
; save area.
|
|
;
|
|
;
|
|
; fbXor describes which rectangle is to be XORed from the work area
|
|
; into the screen. Valid flags are:
|
|
;
|
|
; FB_NEW_PTR, FB_WORK_RECT
|
|
;
|
|
; FB_NEW_PTR and FB_WORK_RECT are mutually exclusive
|
|
;-----------------------------------------------------------------------;
|
|
|
|
fbFlush DB 0
|
|
fbAndRead DB 0
|
|
fbXor DB 0
|
|
FB_OLD_PTR EQU 10000000b
|
|
FB_NEW_PTR EQU 01000000b
|
|
FB_FLUSH_X EQU 00100000b
|
|
FB_FLUSH_Y EQU 00010000b
|
|
FB_OVERLAP EQU 00001000b
|
|
FB_READ_X EQU 00000100b
|
|
FB_READ_Y EQU 00000010b
|
|
FB_WORK_RECT EQU 00000001b
|
|
|
|
; Temporary work buffer. We copy the masks and color data here before
|
|
; we decide how to flip them. !!! Costly use of static space. Use frame
|
|
|
|
public alWorkBuff
|
|
|
|
|
|
alWorkBuff label dword
|
|
REPT (2 * PTR_HEIGHT)
|
|
DD ?
|
|
ENDM
|
|
|
|
|
|
; Table of entry points into and_from_screen inner loop
|
|
|
|
align 4
|
|
and_from_screen_entry_table label dword
|
|
dd and_from_screen_width_0
|
|
dd and_from_screen_width_1
|
|
dd and_from_screen_width_2
|
|
dd and_from_screen_width_3
|
|
dd and_from_screen_width_4
|
|
dd and_from_screen_width_5
|
|
|
|
|
|
; Table of entry points into and_from_save inner loop
|
|
|
|
align 4
|
|
and_from_save_entry_table label dword
|
|
dd and_from_save_width_0
|
|
dd and_from_save_width_1
|
|
dd and_from_save_width_2
|
|
dd and_from_save_width_3
|
|
dd and_from_save_width_4
|
|
dd and_from_save_width_5
|
|
|
|
|
|
; Table of entry points into cps_do_a_pass inner loop
|
|
|
|
align 4
|
|
color_to_screen_entry_table label dword
|
|
dd color_to_screen_width_0
|
|
dd color_to_screen_width_1
|
|
dd color_to_screen_width_2
|
|
dd color_to_screen_width_3
|
|
dd color_to_screen_width_4
|
|
dd color_to_screen_width_5
|
|
|
|
;------------------------------------------------------------------------;
|
|
|
|
.CODE
|
|
|
|
_TEXT$01 SEGMENT DWORD USE32 PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;--------------------------Public-Routine-------------------------------;
|
|
; xyCreateMasks
|
|
;
|
|
; The AND, XOR and COLOR pointer masks are stored in the pointer work
|
|
; areas. The original mask will be pre-rotated for all eight
|
|
; possible alignments within a byte.
|
|
;
|
|
; As the pointer is copied, it will be processed to see if it
|
|
; can be made narrower. After it has been copied, it will be
|
|
; processed to see if it can be made shorter.
|
|
;
|
|
; The following table indicates how the XOR/AND bitmap interacts with
|
|
; the COLOR bitmap for a color system:
|
|
;
|
|
; XOR AND COLOR Result
|
|
; 1 1 x invert screen
|
|
; 0 0 x use x
|
|
; 0 1 x transparent
|
|
; 1 0 x use x
|
|
;
|
|
; From the table, we observe that when the AND bits are on, the
|
|
; corresponding COLOR bits are irrelevant. We preprocess the
|
|
; COLOR bitmap to mask off these bits.
|
|
;
|
|
; When drawing the color pointer, we do the following steps:
|
|
; 1. XOR the destination with XOR mask.
|
|
; 2. AND the destination with AND mask. Note the zero bits
|
|
; would mask off the destination to prepare for the COLOR mask.
|
|
; 3. OR the destination with the COLOR mask. Note it does not
|
|
; affect the inverted or transparent bits since we have masked
|
|
; off the corresponding COLOR bits during preprocessing.
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; AX = width in pels for exclusion hit test
|
|
; DX = height in scans for exclusion hit test
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; create_masks_1_thru_7
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc xyCreateMasks,28,< \
|
|
USES esi edi ebx, \
|
|
ppdev:PTR, \
|
|
pBitsAndXor:PTR, \
|
|
pBitsColor:PTR, \
|
|
cyHeight:DWORD, \
|
|
pulXlate:DWORD, \
|
|
wFlags:WORD, \
|
|
fIsDFB:DWORD >
|
|
|
|
local cyScreen:dword ;height of bitmap in scans
|
|
local lNextScan:dword ;width of bitmap in bytes
|
|
local ajColorBits[PTR_WIDTH*PTR_HEIGHT*4]:byte
|
|
local aulXlate[16]:dword
|
|
|
|
cld
|
|
|
|
mov ecx,ppdev
|
|
mov eax,[ecx].PDEV_sizlSurf.sizl_cy
|
|
mov cyScreen,eax
|
|
mov ecx,[ecx].PDEV_pdsurf
|
|
mov eax,[ecx].dsurf_lNextScan
|
|
mov lNextScan,eax
|
|
|
|
cmp pBitsColor,0
|
|
jne short xycm_have_color
|
|
; Copy the AND/XOR mask into the work buffer
|
|
|
|
mov esi,pBitsAndXor
|
|
mov ecx,cyHeight
|
|
mov bx,wFlags
|
|
shl ecx,1
|
|
mov edi,offset FLAT:alWorkBuff
|
|
rep movsd ;copy AND mask
|
|
jmp short xycm_continue
|
|
|
|
xycm_have_color:
|
|
|
|
; If a color translation vector was given, generate the new bit
|
|
; conversion array
|
|
|
|
mov eax,offset FLAT:aulDefBitMapping
|
|
cld
|
|
mov esi,pulXlate
|
|
or esi,esi
|
|
jz short have_mapping_array
|
|
lea edi,aulXlate
|
|
mov ecx,16
|
|
create_next_bit_mapping:
|
|
lodsd
|
|
mov eax,aulDefBitMapping[eax*4]
|
|
stosd
|
|
dec ecx
|
|
jnz short create_next_bit_mapping
|
|
lea eax,[edi][-16*4]
|
|
have_mapping_array:
|
|
mov pulXlate,eax
|
|
|
|
; Copy the AND mask into the work buffer
|
|
|
|
mov edi,offset FLAT:alWorkBuff
|
|
test wFlags,PTRI_INVERT ;are masks backwards?
|
|
jz short @F ; NO
|
|
mov edi,offset FLAT:alWorkBuff + (4*PTR_HEIGHT)
|
|
@@:
|
|
mov esi,pBitsAndXor
|
|
mov ecx,cyHeight
|
|
rep movsd ;copy AND mask
|
|
|
|
; later on we will flip the AND and XOR masks, so we have to mix them
|
|
; up now else there will be problems later.
|
|
|
|
mov esi,pBitsColor ;Source color bits
|
|
lea edi,ajColorBits ;Where to store color
|
|
mov ecx,cyHeight
|
|
mov dx,wFlags
|
|
|
|
mov eax,fIsDFB
|
|
|
|
push ebp
|
|
mov ebp,pulXlate
|
|
|
|
call vConvertDIBPointer
|
|
|
|
pop ebp
|
|
|
|
xycm_continue:
|
|
mov ebx,cyHeight
|
|
mov dx,wFlags
|
|
cCall vCopyMasks ;Pad and maybe flip masks
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The image we are copying is PTR_WIDTH bytes wide. We must add an
|
|
; extra byte to make it WORK_WIDTH wide. The byte we add will depends
|
|
; on whether this is the AND or the XOR mask. For an AND mask, we add
|
|
; an FF byte on the end of each scan. For an XOR mask, we add a 00
|
|
; byte on the end of each scan. For the COLOR mask, we add a 00 byte on
|
|
; the end of each scan of all planes. These bytes won't alter anything
|
|
; on the screen.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi,offset FLAT:alWorkBuff ;ESI --> AND/XOR mask
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Copy the AND mask over. As we copy it, accumulate the value of
|
|
; each column of the mask. If the entire column is FF, we may be
|
|
; able to discard it.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov edi, offset FLAT:base_and_masks
|
|
mov ecx, PTR_HEIGHT ;Set height for move
|
|
mov ebx, 0FFFFFFFFh ;Accumulate mask columns
|
|
|
|
move_next_and_mask_scan:
|
|
lodsd ;Move explicit part
|
|
stosd
|
|
and ebx, eax
|
|
mov al, 0FFh
|
|
stosb
|
|
.ERRNZ PTR_WIDTH-4
|
|
.ERRNZ WORK_WIDTH-5
|
|
loop move_next_and_mask_scan
|
|
push ebx ;Save AND column mask
|
|
mov edx, offset FLAT:base_and_masks
|
|
mov ecx, (MASK_LENGTH*7)/(WORK_WIDTH*2)
|
|
.ERRNZ (MASK_LENGTH*7) mod (WORK_WIDTH*2)
|
|
cCall create_masks_1_thru_7
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Copy the XOR mask over. As we copy it, accumulate the value of
|
|
; each column of the mask. If the entire column is 00, we may be
|
|
; able to discard it.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov edi, offset FLAT:base_xor_masks
|
|
mov ecx, PTR_HEIGHT ;Set height for move
|
|
xor ebx, ebx ;Accumulate columns of the mask
|
|
|
|
move_next_xor_mask_scan:
|
|
lodsd ;Move explicit part
|
|
stosd
|
|
or ebx, eax
|
|
xor al, al
|
|
stosb
|
|
.ERRNZ PTR_WIDTH-4
|
|
.ERRNZ WORK_WIDTH-5
|
|
loop move_next_xor_mask_scan
|
|
push ebx
|
|
mov edx, offset FLAT:base_xor_masks
|
|
mov ecx, (MASK_LENGTH*7)/(WORK_WIDTH*2)
|
|
.ERRNZ (MASK_LENGTH*7) mod (WORK_WIDTH*2)
|
|
cCall create_masks_1_thru_7
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The masks have been copied. Compute the number of columns which can
|
|
; be discarded. To discard a column, all bits of the AND mask for that
|
|
; column must be 1, and all bits of the XOR mask for the column must be
|
|
; 0. Since we work with bytes in this code, this must be true for an
|
|
; entire byte.
|
|
;
|
|
; Also note that the columns must be processed right to left. We cannot
|
|
; throw out a middle column if its neighbors contain data.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;AND mask, EAX[0] = byte 1, EAX[1] = byte 2
|
|
;AND mask, EAX[2] = byte 3, EAX[3] = byte 4
|
|
;XOR mask, EBX[0] = byte 1, EBX[1] = byte 2
|
|
;XOR mask, EBX[2] = byte 3, EBX[3] = byte 4
|
|
|
|
pop ebx ;EBX XOR mask
|
|
pop eax ;EAX AND mask
|
|
|
|
not eax
|
|
or eax, ebx ;Discard only if both are zero!
|
|
|
|
mov ebx, WORK_WIDTH
|
|
mov edx, PTR_HEIGHT ;assume full mask
|
|
xor ecx, ecx
|
|
;check wFlags
|
|
test wFlags, PTRI_ANIMATE
|
|
jnz short mp_have_sizes
|
|
|
|
; !!! Until conversion of pointer images is handled via bitblt, always
|
|
; !!! treat color cursors as full size
|
|
cmp pBitsColor,0 ;!!!
|
|
jne short mp_have_sizes ;!!!
|
|
|
|
mov edx,eax ;DX = bytes 1 and 2
|
|
shr eax,16 ;AX = bytes 3 and 4
|
|
or ah,ah ;Discard 4th byte of mask?
|
|
jnz short @F ; No
|
|
dec ebx
|
|
or al,al
|
|
jnz short @F
|
|
dec ebx
|
|
or dh,dh
|
|
jnz short @F
|
|
dec ebx
|
|
or dl,dl
|
|
jz move_pointers_done ;AX = DX = 0 for return codes
|
|
@@:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the number of rows which can be discarded off the bottom.
|
|
; To discard a row, all bits of the AND mask for that row must be a
|
|
; 1, and all bits of the XOR mask for that row must be 0.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ PTR_WIDTH AND 1 ;Must be a word multiple
|
|
|
|
dec esi ;Post decremnent, not pre decrement
|
|
dec esi
|
|
lea edi, [esi][-PTR_WIDTH*PTR_HEIGHT] ;Last word of AND mask
|
|
mov ecx, (PTR_WIDTH/2)*PTR_HEIGHT
|
|
mov ax, 0FFFFh ;Processing AND mask
|
|
std
|
|
repe scasw
|
|
mov edx, ecx ;Save count
|
|
mov edi, esi ;--> XOR mask
|
|
mov ecx, (PTR_WIDTH/2)*PTR_HEIGHT
|
|
xor eax, eax ;Processing XOR mask
|
|
repe scasw
|
|
cld ;Take care of this while we remember
|
|
cmp ecx, edx ;Want |cx| to be the largest
|
|
ja short @F
|
|
xchg ecx, edx
|
|
@@:
|
|
;-----------------------------------------------------------------------;
|
|
; CX >> 1 +1
|
|
;
|
|
; 63 31 32 1st word did not match, don't chop any scans
|
|
; 62 31 32 2nd word did not match, don't chop any scans
|
|
; 61 30 31 3rd word did not match, chop 1 scan
|
|
; 60 30 31 4th word did not match, chop 1 scan
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ PTR_WIDTH-4
|
|
|
|
shr ecx, 1
|
|
inc ecx ;ECX = working height
|
|
mov edx, PTR_HEIGHT
|
|
sub edx, ecx ;EDX = # scans chopped off bottom
|
|
xchg ecx, edx ;Height in DX for returning
|
|
|
|
; EBX = working width of the pointer image in bytes. ECX = amount to
|
|
; chop of the bottom of the pointer image. EDX = working height of
|
|
; the pointer image.
|
|
|
|
mp_have_sizes:
|
|
mov eax, ebx
|
|
mov sizlMask.sizl_cx, eax
|
|
mov sizlMaxDelta.sizl_cx, eax
|
|
mov ah, dl
|
|
mov sizbMask, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
mov eax, edx
|
|
mov sizlMask.sizl_cy, eax
|
|
mov sizlMaxDelta.sizl_cy, eax
|
|
neg eax
|
|
add eax, cyScreen
|
|
mov ptlBotRightClip.ptl_y, eax
|
|
mov eax, lNextScan
|
|
sub eax, ebx
|
|
mov ptlBotRightClip.ptl_x, eax
|
|
shr ecx, 1
|
|
mov eax, WORK_WIDTH
|
|
sub eax, ebx
|
|
shr eax, 1
|
|
mov ah, cl
|
|
mov ptbInitOrigin, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
mov eax, ebx
|
|
dec eax
|
|
shl eax, 3 ;Bit count is needed
|
|
|
|
shl edx, 16 ;Return value in upper word of EAX
|
|
or eax, edx ; is cyPointer, lower word of EAX
|
|
push eax ; is cxPointer.
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Finally, copy the COLOR mask over. As we copy it, mask off the
|
|
; corresponding AND bits in the COLOR mask since we do not use that
|
|
; color bit if the AND bit is on.
|
|
;
|
|
; XOR AND COLOR
|
|
; 1 1 invert screen
|
|
; 0 0 use color
|
|
; 0 1 transparent
|
|
; 1 0 use color
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ecx, pBitsColor
|
|
jecxz move_color_pointer_done ;pBitsColor was set to null
|
|
lea esi, ajColorBits
|
|
mov edi, offset FLAT:base_clr_masks
|
|
push ebp ;Need extra loop counter
|
|
mov ebp, BITS_PEL
|
|
|
|
move_next_color_mask_plane:
|
|
mov ecx, PTR_HEIGHT ;Set height for move
|
|
mov ebx, offset FLAT:base_and_masks
|
|
sub ebx, edi ;make it relative
|
|
|
|
move_next_color_mask_scan:
|
|
ifdef WITH_AND_MASK
|
|
lodsw ;Copy a scan from the current plane
|
|
mov dx, [ebx][edi] ;Mask off the corresponding AND bits
|
|
not dx
|
|
and ax, dx
|
|
stosw
|
|
lodsw
|
|
mov dx, [ebx][edi]
|
|
not dx
|
|
and ax, dx
|
|
stosw
|
|
else
|
|
movsd
|
|
endif
|
|
xor al, al
|
|
stosb
|
|
|
|
.ERRNZ PTR_WIDTH-4
|
|
.ERRNZ WORK_WIDTH-5
|
|
|
|
add esi, (BITS_PEL-1)*PTR_WIDTH
|
|
loop move_next_color_mask_scan
|
|
sub esi, (BITS_PEL*PTR_WIDTH*PTR_HEIGHT)-PTR_WIDTH
|
|
dec ebp
|
|
jnz short move_next_color_mask_plane
|
|
pop ebp ;Restore register
|
|
|
|
mov edx, offset FLAT:base_clr_masks
|
|
mov ecx, (CLR_MASK_LENGTH*7)/(WORK_WIDTH*2)
|
|
|
|
.ERRNZ (CLR_MASK_LENGTH*7) MOD (WORK_WIDTH*2)
|
|
|
|
cCall create_masks_1_thru_7
|
|
|
|
move_color_pointer_done:
|
|
|
|
pop eax ;return results in EAX
|
|
|
|
move_pointers_done:
|
|
mp_exit:
|
|
cRet xyCreateMasks
|
|
|
|
endProc xyCreateMasks
|
|
|
|
;-------------------------Private-Routine-------------------------------;
|
|
; Copy the masks to the work buffer and adjust for use. Two things may
|
|
; need to be done:
|
|
;
|
|
; 1) The masks could be inverted.
|
|
; 2) The masks may need to be padded out
|
|
;
|
|
; Entry:
|
|
; EBX = number of scan lines in each mask
|
|
; DX = flags (PTRI_INVERT)
|
|
;
|
|
; Returns:
|
|
; None
|
|
;
|
|
; Error Returns:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc vCopyMasks
|
|
mov ecx,ebx ;Needed for padding calculations
|
|
test dx,PTRI_INVERT ;are masks backwards?
|
|
jz short copy_no_flip
|
|
|
|
; This is really annoying. Not only are the masks inverted, but they
|
|
; are stored in the wrong order. First get the AND and XOR masks into
|
|
; the correct order.
|
|
|
|
mov ecx,PTR_HEIGHT
|
|
mov esi,offset FLAT:alWorkBuff
|
|
mov edi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
|
|
|
|
@@:
|
|
mov eax,[esi]
|
|
mov edx,[edi]
|
|
mov [edi],eax
|
|
mov [esi],edx
|
|
add esi,4
|
|
add edi,4
|
|
loop @B
|
|
|
|
; Next, flip them so they are right-side up.
|
|
|
|
mov ecx,ebx
|
|
mov esi,offset FLAT:alWorkBuff
|
|
cCall vFlipMask ;flip AND mask
|
|
|
|
mov ecx,ebx
|
|
mov esi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
|
|
cCall vFlipMask ;flip XOR mask
|
|
|
|
; Now pad out the masks so no junk appears on the screen
|
|
|
|
copy_no_flip:
|
|
|
|
mov eax,0FFFFFFFFh ;pad AND mask
|
|
mov ecx,PTR_HEIGHT
|
|
sub ecx,ebx
|
|
mov edi,offset FLAT:alWorkBuff
|
|
lea edi,[edi+4*ebx]
|
|
rep stosd
|
|
|
|
xor eax,eax ;pad XOR mask
|
|
mov ecx,PTR_HEIGHT
|
|
sub ecx,ebx
|
|
mov edi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
|
|
lea edi,[edi+4*ebx]
|
|
rep stosd
|
|
|
|
cRet vCopyMasks
|
|
|
|
endProc vCopyMasks
|
|
|
|
;-------------------------Private-Routine-------------------------------;
|
|
; Flip the scans in the buffer
|
|
;
|
|
; Entry:
|
|
; ESI --> start of first scan line
|
|
; ECX = number of scan lines
|
|
;
|
|
; Returns:
|
|
; None
|
|
;
|
|
; Error Returns:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc vFlipMask
|
|
lea edi,[esi+4*ecx]
|
|
shr ecx,1
|
|
|
|
flip_next_scan:
|
|
sub edi,4 ;decrement target pointer
|
|
|
|
mov eax,[esi] ;Load
|
|
mov edx,[edi]
|
|
mov [edi],eax ;Swap
|
|
mov [esi],edx ;Save
|
|
|
|
add esi,4 ;increment source pointer
|
|
|
|
loop flip_next_scan
|
|
|
|
cRet vFlipMask
|
|
|
|
endProc vFlipMask
|
|
|
|
page
|
|
|
|
;--------------------------Public-Routine-------------------------------;
|
|
; create_masks_1_thru_7
|
|
;
|
|
; The pointer shape has been copied into our memory. Now pre-rotate
|
|
; the pointer for all the different alignments. Simply put:
|
|
;
|
|
; pointer image fill byte
|
|
;
|
|
; |ABCDEFGH|IJKLMNOP|QRSTUVWX|YZabcdef|00000000|
|
|
;
|
|
; becomes this for (x mod 8) = 1
|
|
;
|
|
; |0ABCDEFG|HIJKLMNO|PQRSTUVW|XYZabcde|f0000000|
|
|
;
|
|
; and this for (x mod 8) = 2
|
|
;
|
|
; |00ABCDEF|GHIJKLMN|OPQRSTUV|WXYZabcd|ef000000|
|
|
;
|
|
; Entry:
|
|
; EDI --> first byte of mask for phase alignment 1
|
|
; EDX --> first byte of mask for phase alignment 0
|
|
; ECX = (mask length * 7) / (WORK_WIDTH * 2)
|
|
; AL = fill value (00 or FF)
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; BX,SI,BP
|
|
; Registers Destroyed:
|
|
; AX,CX,DX,DI
|
|
; Calls:
|
|
; none
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc create_masks_1_thru_7
|
|
|
|
; Since the masks are contiguous, we can do it as one very long loop,
|
|
; where the results of rotating the previous mask by one becomes the
|
|
; source for the next rotate by one.
|
|
|
|
xchg esi, edx
|
|
add al, al ;Set initial 'C' value
|
|
|
|
rotate_next_two_scans:
|
|
lodsw
|
|
rcr al, 1
|
|
rcr ah, 1
|
|
stosw
|
|
|
|
lodsw
|
|
rcr al, 1
|
|
rcr ah, 1
|
|
stosw
|
|
|
|
lodsw
|
|
rcr al, 1
|
|
rcr ah, 1
|
|
stosw
|
|
|
|
lodsw
|
|
rcr al, 1
|
|
rcr ah, 1
|
|
stosw
|
|
|
|
lodsw
|
|
rcr al, 1
|
|
rcr ah, 1
|
|
stosw
|
|
|
|
loop rotate_next_two_scans
|
|
|
|
.ERRNZ (WORK_WIDTH*2)-10
|
|
|
|
xchg esi, edx
|
|
|
|
cRet create_masks_1_thru_7
|
|
|
|
endProc create_masks_1_thru_7
|
|
page
|
|
|
|
;--------------------------Public-Routine-------------------------------;
|
|
; vYankPointer
|
|
;
|
|
; Move the pointer off the right edge of the screen
|
|
;
|
|
; Returns:
|
|
; per vDrawPointer
|
|
; Error Returns:
|
|
; per vDrawPointer
|
|
; Registers Preserved:
|
|
; per vDrawPointer
|
|
; Registers Destroyed:
|
|
; per vDrawPointer
|
|
; Calls:
|
|
; per vDrawPointer
|
|
; Restrictions:
|
|
; per vDrawPointer
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc vYankPointer,8,< \
|
|
ppdev:ptr PDEV, \
|
|
flPtr:DWORD >
|
|
|
|
mov eax,ppdev
|
|
cCall vDrawPointer,<eax,[eax].PDEV_sizlsurf.sizl_cx, \
|
|
[eax].PDEV_sizlsurf.sizl_cy,flPtr>
|
|
yp_exit:
|
|
cRet vYankPointer
|
|
|
|
endProc vYankPointer
|
|
|
|
page
|
|
|
|
;--------------------------Public-Routine-------------------------------;
|
|
; vDrawPointer
|
|
;
|
|
; The pointer shape is drawn on the screen at the given coordinates.
|
|
; If it currently is displayed on the screen, it will be removed
|
|
; from the old location first.
|
|
;
|
|
; Entry:
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; compute_rects
|
|
; clip_rects
|
|
; and_into_work
|
|
; copy_things_around
|
|
; xor_to_screen
|
|
; color_pointer_to_screen
|
|
; Restrictions:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc vDrawPointer,16,< \
|
|
USES esi edi ebx, \
|
|
ppdev:ptr PDEV, \
|
|
ptlX:DWORD, \
|
|
ptlY:DWORD, \
|
|
flPtr:DWORD >
|
|
|
|
local lNextScan :dword ;width of bitmap in bytes
|
|
local ulNextSrcScan :dword ;offset to next source scan line
|
|
local jPostWrapWidth :dword ;post-wrap width
|
|
local pSaveAddr :dword ;virtual address of save area
|
|
local jSaveSourceXY :dword ;X and Y coordinates of source point in
|
|
; save area
|
|
local jWorkSourceXY :dword ;X and Y coordinates of source point in
|
|
; work area
|
|
local jNextSaveSourceY :dword ;Y coordinate of start source point in
|
|
; save area for next bank
|
|
local jNextWorkSourceY :dword ;Y coordinate of start source point in
|
|
; work area for next bank
|
|
local pWorkingSave :dword ;save area virtual address
|
|
local ulScanMinusWorkWidth :dword ;distance to next scan, minus the
|
|
; width of the work area
|
|
local ulCurrentTopScan :dword ;top scan line to which to draw in
|
|
; current bank
|
|
local jScansInBank :dword ;# of scan to do in current bank
|
|
local cjTotalScans :dword ;# of scans left in operation
|
|
local ulPtrBankScan :dword ;last scan line in pointer work bank
|
|
local pdsurf :ptr DEVSURF ;pointer to surface structure to which
|
|
; we're drawing
|
|
;variables used by cps_do_a_pass
|
|
local ulDeltaScreen :dword ;offset from one scan to next
|
|
local ulOffsetSave :dword ;offset in save area
|
|
local ulOffsetMask :dword ;offset within mask
|
|
local iPlaneMask :dword
|
|
;variables used by
|
|
; color_pointer_to_screen
|
|
local pDest :dword ;pointer to destination address
|
|
local prclSource :dword ;pointer to source rectangle
|
|
local cyScreen :dword ;height of screen in scan lines
|
|
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cld
|
|
|
|
mov ecx,ppdev
|
|
mov eax,[ecx].PDEV_sizlSurf.sizl_cy
|
|
mov cyScreen,eax
|
|
|
|
mov ecx,[ecx].PDEV_pdsurf
|
|
mov pdsurf,ecx ;pointer to target surface
|
|
|
|
mov eax,[ecx].dsurf_ulPtrBankScan
|
|
mov ulPtrBankScan,eax ;last scan line in pointer work bank
|
|
|
|
mov eax,[ecx].dsurf_lNextScan
|
|
mov lNextScan,eax ;width of bitmap
|
|
|
|
mov eax, flPtr
|
|
mov flPointer,eax ;save flags
|
|
mov edi, ppdNew ;--> new pointer's data goes here
|
|
mov esi, ppdOld ;--> old pointer's data
|
|
mov eax, ptlX ;EAX = ptlX
|
|
mov ebx, eax
|
|
and ebx, 7
|
|
mov edx, pabAndMasks[ebx * 4]
|
|
mov pAndXor, edx
|
|
mov edx, pabClrMasks[ebx * 4]
|
|
mov pColor, edx
|
|
mov ebx, PD_VALID ;Assume visible
|
|
sar eax, 3 ;Compute starting byte address (set 'S')
|
|
mov [edi].pd_rd.rd_ptlScreen.ptl_x, eax
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute any X clipping parameters for the new pointer image.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
js short clip_lhs_of_pointer ;If X is negative, lhs clipping needed
|
|
sub eax, ptlBotRightClip.ptl_x
|
|
jle short done_x_clipping
|
|
mov bh,PD_CLIP_RIGHT ;EAX = amount to clip off rhs
|
|
jmp short finish_x_clip
|
|
|
|
clip_lhs_of_pointer:
|
|
neg eax ;Want |eax|
|
|
mov bh, PD_CLIP_LEFT
|
|
|
|
finish_x_clip:
|
|
cmp eax, sizlMask.sizl_cx ;Width of pointer in bytes
|
|
jge short not_visible ;Clipped away too much
|
|
or bl, bh
|
|
done_x_clipping:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute any Y clipping parameters for the new pointer image.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov eax, ptlY
|
|
mov [edi].pd_rd.rd_ptlScreen.ptl_y, eax
|
|
or eax, eax
|
|
js short clip_top_of_pointer ;If Y is negative, top clipping needed
|
|
sub eax, ptlBotRightClip.ptl_y
|
|
jle short done_y_clipping
|
|
mov bh, PD_CLIP_BOTTOM ;AX = amount to clip off bottom
|
|
jmp short finish_y_clip
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; not_visible - the pointer will be totally off the screen. All we
|
|
; have to do is to determine if any part of the old pointer is visible
|
|
; and remove it if so.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
not_visible:
|
|
test [esi].pd_fb, PD_VALID
|
|
jz draw_pointer_exit ;No new, no old
|
|
xor eax, eax
|
|
mov [edi].pd_fb, al ;Clear PD_VALID flag, clipping flags
|
|
mov WORD PTR fbAndRead, ax ;Nothing to read/and/xor
|
|
|
|
.ERRNZ fbXor-fbAndRead-1
|
|
|
|
mov fbFlush, FB_OLD_PTR ;Write old to screen
|
|
jmp short rectangles_been_computed
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Continue with Y clipping
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_top_of_pointer:
|
|
neg eax ;Want |eax|
|
|
mov bh,PD_CLIP_TOP
|
|
|
|
finish_y_clip:
|
|
cmp eax, sizlMask.sizl_cy ;Height of pointer in scans
|
|
jge short not_visible ;Clipped away too much
|
|
or bl, bh
|
|
|
|
done_y_clipping:
|
|
mov [edi].pd_fb, bl ;Set clipping flags and show valid
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; It looks like some portion of the pointer image will be visible.
|
|
; Initialize some of the new pointer's POINTER_DATA structure.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ax, sizbMask ;ptbSave will be set by compute_rects
|
|
mov [edi].pd_rd.rd_sizb, ax
|
|
|
|
.ERRNZ (SIZE SIZEB) - 2
|
|
|
|
xor ax, ax
|
|
mov [edi].pd_rd.rd_ptbWork, ax
|
|
|
|
.ERRNZ (SIZE POINTB) - 2
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the rectangles describing how things overlap and then clip
|
|
; them.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
call compute_rects
|
|
rectangles_been_computed:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Set WRITE mode of EGA/VGA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov dx, EGA_BASE + GRAF_ADDR
|
|
mov ax, DR_SET SHL 8 + GRAF_DATA_ROT
|
|
out dx, ax
|
|
|
|
mov ax, M_PROC_WRITE SHL 8 + GRAF_MODE
|
|
out dx, ax
|
|
|
|
mov ax, 0FF00h + GRAF_BIT_MASK
|
|
out dx, ax
|
|
|
|
mov ax, GRAF_ENAB_SR
|
|
out dx, ax
|
|
|
|
mov dl, SEQ_ADDR
|
|
mov ax, MM_ALL SHL 8 + SEQ_MAP_MASK
|
|
out dx, ax
|
|
|
|
call clip_rects
|
|
|
|
mov eax,flPointer ;lousy hack
|
|
or eax,eax
|
|
jnz short draw_color_pointer ;Color pointer?
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Draw B/W Pointer
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AND from the save area and the screen into the work area
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, fbAndRead
|
|
or al, al
|
|
jz short done_and_portion
|
|
call and_into_work
|
|
done_and_portion:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Copy from save area to the screen and from the screen to the save
|
|
; area.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ax, WORD PTR fbFlush ;Assume nothing to copy to/from save
|
|
|
|
.ERRNZ fbAndRead-fbFlush-1
|
|
|
|
or ah, al
|
|
jz short copied_things_around
|
|
call copy_things_around
|
|
copied_things_around:
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; XOR from the work area to the screen
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, fbXor
|
|
or al, al
|
|
jz short pointer_drawn
|
|
call xor_to_screen
|
|
jmp short pointer_drawn
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Draw Color Pointer
|
|
;-----------------------------------------------------------------------;
|
|
|
|
draw_color_pointer:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Copy from save area to the screen and from the screen to the save area.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ax, WORD PTR fbFlush ;Assume nothing to copy to/from save
|
|
|
|
.ERRNZ fbAndRead-fbFlush-1
|
|
|
|
or ah, al
|
|
jz short things_copied_around
|
|
call copy_things_around
|
|
things_copied_around:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Draw color pointer to screen
|
|
;-----------------------------------------------------------------------;
|
|
|
|
test fbXor, 0FFh
|
|
jz short pointer_drawn
|
|
call color_pointer_to_screen ;Planes must all be enabled
|
|
|
|
pointer_drawn:
|
|
mov eax,ppdNew
|
|
mov edx,ppdOld
|
|
mov ppdOld,eax
|
|
mov ppdNew,edx
|
|
draw_pointer_exit:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Reset WRITE mode of EGA/VGA to WRITE MODE 0, READ MODE 1
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, MM_ALL ;Set Map Mask for all write
|
|
mov dx, EGA_BASE + SEQ_DATA
|
|
out dx, al
|
|
|
|
mov dx, EGA_BASE + GRAF_ADDR
|
|
mov ax, DR_SET SHL 8 + GRAF_DATA_ROT
|
|
out dx, ax
|
|
|
|
mov ax, M_PROC_WRITE SHL 8 + GRAF_MODE
|
|
out dx, ax
|
|
|
|
mov ax, 0FF00h + GRAF_BIT_MASK
|
|
out dx, ax
|
|
|
|
mov ax, GRAF_ENAB_SR
|
|
out dx, ax
|
|
|
|
cRet vDrawPointer
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The following routines would be procs, outside the scope of
|
|
; vDrawPointer, but then they couldn't access vDrawPointer's stack
|
|
; frame, which they need to.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; compute_rects
|
|
;
|
|
; This routine computes the rectangles which describe what needs to be
|
|
; read/ANDed/XORed/written. The rectangles are unclipped. Clipping
|
|
; must be performed by a different routine.
|
|
;
|
|
; Entry:
|
|
; AX = 0
|
|
; SI --> currently displayed pointer's rectangle data
|
|
; DI --> new pointer's rectangle data
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
compute_rects:
|
|
|
|
push ebp
|
|
|
|
mov WORD PTR fbFlush, ax ;Assume nothing to restore to screen
|
|
|
|
.ERRNZ fbAndRead-fbFlush-1 ;Assume nothing to read/And to work
|
|
|
|
mov fbXor, FB_NEW_PTR ;Assume new pointer is XORed to screen
|
|
test [esi].pd_fb, PD_VALID
|
|
jz short old_pointer_is_invalid
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; There is a pointer currently displayed on the screen. If the new
|
|
; pointer is far enough away from the old pointer, then we won't have
|
|
; to deal with overlap.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
old_pointer_is_valid:
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_x
|
|
sub eax, [esi].pd_rd.rd_ptlScreen.ptl_x
|
|
mov bl, al ;BL = delta x
|
|
or eax, eax ;EAX = |EAX|
|
|
jns short @F
|
|
neg eax
|
|
@@:
|
|
cmp eax, sizlMaxDelta.sizl_cx
|
|
jae rects_are_disjoint
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_y
|
|
sub eax, [esi].pd_rd.rd_ptlScreen.ptl_y
|
|
mov bh, al ;BH = delta y
|
|
or eax, eax ;EAX = |EAX|
|
|
jns short @F
|
|
neg eax
|
|
@@:
|
|
cmp eax, sizlMaxDelta.sizl_cy
|
|
jb short rects_overlap ;(or are identical)
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The rectangles will be disjoint. Set up to restore under the old
|
|
; pointer, copy the new rectangle to the save area, and AND it into
|
|
; the work area.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
rects_are_disjoint:
|
|
mov fbFlush, FB_OLD_PTR
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The save area image is invalid, so we won't have to copy it to the
|
|
; screen or AND some part of it into the work area. We'll simply want
|
|
; to copy the new area to the save area and AND it into the work area.
|
|
; This can be treated the same as if the rectangles are identical,
|
|
; except we want to reset the origin within the save buffer.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
old_pointer_is_invalid:
|
|
mov ax, ptbInitOrigin ;Reset origin within the save area
|
|
mov [edi].pd_rd.rd_ptbSave,ax
|
|
|
|
.ERRNZ (SIZE POINTB) - 2
|
|
|
|
mov fbAndRead, FB_NEW_PTR ;Copy new ptr to save and XOR to work
|
|
jmp compute_rects_exit
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The rectangles overlap in some manner. Compute how the rectangles,
|
|
; will overlap, setting up the various needed rectangle structures as
|
|
; we go.
|
|
;
|
|
; The only hope we have of computing the overlap rectangle is to
|
|
; initialize it to some known state and adjusting it as we process
|
|
; dx and dy. We will initialize it to be the upper left hand corner
|
|
; of the old pointer rectangle.
|
|
;
|
|
; Currently:
|
|
; AX = old pointer's pd_rd.rd_ptbSave
|
|
; BH = dy
|
|
; BL = dx (negative)
|
|
; SI --> old pointer's rd_ptlScreen
|
|
; DI --> new pointer rectangle
|
|
;-----------------------------------------------------------------------;
|
|
|
|
rects_overlap:
|
|
|
|
; Set old pointer's save buffer (X,Y) into the overlap rectangle.
|
|
; Also set this as the save buffer origin for the new pointer rectangle.
|
|
|
|
lodsw
|
|
|
|
.ERRNZ pd_rd.rd_ptbSave
|
|
|
|
mov rdOverlap.rd_ptbSave, ax
|
|
mov [edi].pd_rd.rd_ptbSave, ax
|
|
mov dx, ax
|
|
|
|
; Set old pointer's screen (X,Y) into the overlap rectangle as the
|
|
; screen origin.
|
|
|
|
lodsd
|
|
|
|
.ERRNZ rd_ptlScreen-rd_ptbSave-2
|
|
.ERRNZ ptl_x
|
|
|
|
mov rdOverlap.rd_ptlScreen.ptl_x, eax
|
|
mov ebp, eax
|
|
lodsd
|
|
|
|
.ERRNZ ptl_y-ptl_x-4
|
|
|
|
mov rdOverlap.rd_ptlScreen.ptl_y, eax
|
|
mov esi, eax
|
|
|
|
; Set the mask width and height into the overlap rectangle
|
|
|
|
mov ax, sizbMask
|
|
mov rdOverlap.rd_sizb, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
.ERRNZ (SIZE SIZEB) - 2
|
|
|
|
mov ecx, eax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
; Set the work buffer origin to be zero
|
|
|
|
xor eax, eax
|
|
mov rdOverlap.rd_ptbWork, ax
|
|
|
|
; Show that the overlap rectangle exists and should be ANDed into the
|
|
; work area, then dispatch based on dx,dy.
|
|
|
|
mov fbAndRead, FB_OVERLAP
|
|
or bl, bl ; Dispatch based on dx
|
|
jg short moved_right
|
|
jl short moved_left
|
|
jmp processed_x_overlap
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The starting X of the new rectangle is to be set as the new lhs.
|
|
;
|
|
; * nnnnn $ onononono oooooooo * = start of new rectangle
|
|
; o o $ = start of old rectangle
|
|
; n | o | n | o
|
|
; n | n o | o
|
|
; n | o O n o
|
|
; n n v o F o
|
|
; n R o e n l o
|
|
; n e n r o u o
|
|
; n a o l n s o
|
|
; n d n a o h o
|
|
; n o p n o
|
|
; n | n o | o
|
|
; n | o | n | o
|
|
; n | n | o | o
|
|
; n o n o
|
|
; nnnnnnnn nonononono oooooooo
|
|
;
|
|
; |-- dx -| |-- dx -|
|
|
; |-sizbMask.sizb_cx-|
|
|
;
|
|
;
|
|
; Currently:
|
|
; AX = 0
|
|
; BH = dy
|
|
; BL = dx (negative)
|
|
; CH = buffer height
|
|
; CL = buffer width
|
|
; DH = old pointer's Y coordinate in save area
|
|
; DL = old pointer's X coordinate in save area
|
|
; SI = old pointer's Y screen coordinate
|
|
; BP = old pointer's X screen coordinate
|
|
; DI = --> new pointer's RECT_DATA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
moved_left:
|
|
|
|
; The Read buffer will map into the work area at (0,0).
|
|
|
|
mov rdReadX.rd_ptbWork, ax
|
|
|
|
; The width of the overlap area is sizbMask.sizb_cx - |dx|.
|
|
|
|
mov al, bl ;BL = dx (which is negative)
|
|
add al, cl ;CL = sizbMask.sizb_cx
|
|
mov rdOverlap.rd_sizb.sizb_cx, al
|
|
|
|
; The flush rectangle's X is ptlScreen.ptl_x + sizbMask.sizb_cx - |dx|.
|
|
|
|
add eax, ebp ;AX = sizbMask.sizb_cx - |dx|
|
|
mov rdFlushX.rd_ptlScreen.ptl_x, eax
|
|
|
|
; Compute where in the save buffer the new lhs will map to. We must
|
|
; update the new pointer's rectangle to reflect where this origin is.
|
|
|
|
mov eax, edx ;DX = old ptbSave
|
|
add al, bl ;BL = dx (negative)
|
|
add ah, bh ;BH = dy
|
|
and eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
|
|
mov [edi].pd_rd.rd_ptbSave.ptb_x, al
|
|
mov rdReadX.rd_ptbSave, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The origin of the flush rectangle is sizbMask.sizb_cx bytes away
|
|
; from the origin of the read rectangle.
|
|
|
|
add al, cl
|
|
and al, SAVE_BUFFER_WIDTH-1 ;Handle any wrap
|
|
mov ah, dh
|
|
mov rdFlushX.rd_ptbSave, ax
|
|
|
|
; Compute |dx|. This is the width of the read and flush rectangles.
|
|
; The height will be set to the working height. |dx| is also the
|
|
; overlap rectangle's work area X coordinate.
|
|
|
|
mov al, bl ;BL = dx (negative)
|
|
neg al ;AL = |dx|
|
|
mov ah, ch ;CH = sizbMask.sizb_cy
|
|
mov rdFlushX.rd_sizb, ax
|
|
mov rdReadX.rd_sizb, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
mov rdOverlap.rd_ptbWork.ptb_x, al
|
|
|
|
; The Read buffer's screen address is the ptlScreen stored in the new
|
|
; pointer's RECT_DATA.
|
|
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_x
|
|
jmp short finish_x_overlap
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The starting X of the new rectangle is somewhere in the middle
|
|
; of the old rectangle.
|
|
;
|
|
; $ ooooo * onononono nnnnnnn * = start of new rectangle
|
|
; o n o n $ = start of old rectangle
|
|
; o | o | n | n
|
|
; o | n o | n
|
|
; o o O n | n
|
|
; o F n v o n
|
|
; o l o e n R n
|
|
; o u n r o e n
|
|
; o s o l n a n
|
|
; o h n a o d n
|
|
; o o p n n
|
|
; o | n o | n
|
|
; o | o | n | n
|
|
; o | n | o | n
|
|
; o o n n
|
|
; oooooooo nonononono nnnnnnn
|
|
;
|
|
; |-- dx -| |-- dx -|
|
|
; |-sizbMask.sizb_cx-|
|
|
;
|
|
;
|
|
; Currently:
|
|
; AX = 0
|
|
; BH = dy
|
|
; BL = dx (positive)
|
|
; CH = buffer height
|
|
; CL = buffer width
|
|
; DH = old pointer's Y coordinate in save area
|
|
; DL = old pointer's X coordinate in save area
|
|
; SI = old pointer's Y screen coordinate
|
|
; BP = old pointer's X screen coordinate
|
|
; DI = --> new pointer's RECT_DATA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
moved_right:
|
|
|
|
; The screen X origin of the overlap rectangle is the new rectangle's
|
|
; X coordinate, or the old rectangle's X coordinate + |dx|.
|
|
|
|
mov al, bl
|
|
add rdOverlap.rd_ptlScreen.ptl_x, eax
|
|
|
|
; The width of the read and flush buffers is |dx|. The height is
|
|
; just the working height.
|
|
|
|
mov ah, ch ;CH = sizbMask.sizb_cy
|
|
mov rdFlushX.rd_sizb, ax
|
|
mov rdReadX.rd_sizb, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
; Compute where the new lhs is in the save area. This will be the lhs
|
|
; of both the new rectangle and the overlap area.
|
|
|
|
add al, dl ;DL = ptbSave.ptb_x
|
|
and al, SAVE_BUFFER_WIDTH-1 ;Handle any wrap
|
|
mov [edi].pd_rd.rd_ptbSave.ptb_x, al
|
|
mov rdOverlap.rd_ptbSave.ptb_x, al
|
|
|
|
; The data to be flushed will come from the lhs of the old rectangle
|
|
|
|
mov eax, edx
|
|
mov rdFlushX.rd_ptbSave, ax
|
|
|
|
; The data to be read will go at the old lhs + sizbMask.sizb_cx. The
|
|
; Y component will be the new Y.
|
|
|
|
add al, cl
|
|
add ah, bh
|
|
and eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
|
|
mov rdReadX.rd_ptbSave, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The X screen origin of the flush buffer is the old ptlScreen.ptl_x
|
|
|
|
mov rdFlushX.rd_ptlScreen.ptl_x, ebp
|
|
|
|
; The width of the overlap rectangle is sizbMask.sizb_cx - |dx|. This
|
|
; is also the X offset into the work area of the read rectangle.
|
|
; The Y offset is zero.
|
|
|
|
mov al, cl
|
|
sub al, bl
|
|
mov rdOverlap.rd_sizb.sizb_cx, al
|
|
movsx eax, al
|
|
mov rdReadX.rd_ptbWork, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The screen Y origin of the read rectangle is the new rectangle's Y
|
|
; coordinate. The X coordinate can be computed as the old rectangles
|
|
; X coordinate + the save width
|
|
|
|
mov al, cl
|
|
add eax, ebp
|
|
|
|
finish_x_overlap:
|
|
mov rdReadX.rd_ptlScreen.ptl_x, eax
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_y
|
|
mov rdReadX.rd_ptlScreen.ptl_y, eax
|
|
|
|
; The Y address of the flush rectangle on the screen is ptlScreen.ptl_y.
|
|
|
|
mov rdFlushX.rd_ptlScreen.ptl_y, esi
|
|
|
|
; Set the flags to show that there is some form of X overlap. We want
|
|
; to show that there is some X rectangle to be read/flushed, and that
|
|
; there is some overlap rectangle to be processed.
|
|
|
|
or WORD PTR fbFlush, (FB_READ_X SHL 8) + FB_FLUSH_X
|
|
|
|
.ERRNZ fbAndRead-fbFlush-1
|
|
|
|
xor eax, eax
|
|
|
|
processed_x_overlap:
|
|
or bh, bh
|
|
jg short moved_down
|
|
jz short processed_y_overlap_relay
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The starting Y of the new rectangle is to be set as the new top.
|
|
;
|
|
; * = start of new rectangle
|
|
; $ = start of old rectangle
|
|
;
|
|
; $ oooooooooooooooooooooooooo --- ---
|
|
; o o | |
|
|
; o -------- Read ---------- o dy |
|
|
; o | |
|
|
; * onononononononononononono ---
|
|
; n sizbMask.sizb_cy - dy
|
|
; n o
|
|
; o ------- Overlap -------- n |
|
|
; n o |
|
|
; o n |
|
|
; ononononononononononononon --- ---
|
|
; n n |
|
|
; n -------- Write --------- n dy
|
|
; n n |
|
|
; nnnnnnnnnnnnnnnnnnnnnnnnnnnn ---
|
|
;
|
|
;
|
|
;
|
|
; Currently:
|
|
; AX = 0
|
|
; BH = dy (negative)
|
|
; BL = dx
|
|
; CH = buffer height
|
|
; CL = buffer width
|
|
; DH = old pointer's Y coordinate in save area
|
|
; DL = old pointer's X coordinate in save area
|
|
; SI = old pointer's Y screen coordinate
|
|
; BP = old pointer's X screen coordinate
|
|
; DI = --> new pointer's RECT_DATA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
moved_up:
|
|
|
|
; The Read buffer will map into the work area at (0,0).
|
|
|
|
mov rdReadY.rd_ptbWork, ax
|
|
|
|
; The height of the overlap area is sizbMask.sizb_cy - |dy|.
|
|
|
|
mov al, bh ;BH = dy (which is negative)
|
|
add al, ch ;CH = sizbMask.sizb_cy
|
|
mov rdOverlap.rd_sizb.sizb_cy, al
|
|
|
|
; The flush rectangle's Y is ptlScreen.ptl_y + sizbMask.sizb_cy - |dy|.
|
|
|
|
add eax, esi ;EAX = sizbMask.sizb_cy - |dy|
|
|
mov rdFlushY.rd_ptlScreen.ptl_y, eax
|
|
|
|
; Compute where in the save buffer the new top will map to. We must
|
|
; update the new pointer's rectangle to reflect where this origin is.
|
|
|
|
mov eax, edx ;DX = old ptbSave
|
|
add ah, bh ;BH = dy (negative)
|
|
add al, bl
|
|
and eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
|
|
mov [edi].pd_rd.rd_ptbSave.ptb_y, ah
|
|
mov rdReadY.rd_ptbSave, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The origin of the flush rectangle is sizbMask.sizb_cy scans away
|
|
; from the origin of the read rectangle.
|
|
|
|
add ah, ch
|
|
and ah, SAVE_BUFFER_HEIGHT-1 ;Handle any wrap
|
|
mov al, dl
|
|
mov rdFlushY.rd_ptbSave, ax
|
|
|
|
; Compute |dy|. This is the height of the read and flush rectangles.
|
|
; The width will be set to the working width. |dy| is also the
|
|
; overlap rectangle's work area Y coordinate.
|
|
|
|
mov ah, bh ;BH = dy
|
|
neg ah ;Make it |dy|
|
|
mov al, cl ;CL = sizbMask.sizb_cx
|
|
mov rdFlushY.rd_sizb, ax
|
|
mov rdReadY.rd_sizb, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
mov rdOverlap.rd_ptbWork.ptb_y, ah
|
|
|
|
; The Read buffer's screen address is the ptlScreen stored in the new
|
|
; pointer's RECT_DATA.
|
|
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_y
|
|
jmp short finish_y_overlap
|
|
|
|
processed_y_overlap_relay:
|
|
jmp processed_y_overlap
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The starting Y of the new rectangle is somewhere in the middle
|
|
; of the old rectangle.
|
|
;
|
|
; * = start of new rectangle
|
|
; $ = start of old rectangle
|
|
;
|
|
; $ oooooooooooooooooooooooooo --- ---
|
|
; o o | |
|
|
; o -------- Write --------- o dy |
|
|
; o | |
|
|
; * onononononononononononono ---
|
|
; n sizbMask.sizb_cy - dy
|
|
; n o
|
|
; o ------- Overlap -------- n |
|
|
; n o |
|
|
; o n |
|
|
; ononononononononononononon --- ---
|
|
; n n |
|
|
; n -------- Read ---------- n dy
|
|
; n n |
|
|
; nnnnnnnnnnnnnnnnnnnnnnnnnnnn ---
|
|
;
|
|
;
|
|
; Currently:
|
|
; AX = 0
|
|
; BH = dy (positive)
|
|
; BL = dx
|
|
; CH = buffer height
|
|
; CL = buffer width
|
|
; DH = old pointer's Y coordinate in save area
|
|
; DL = old pointer's X coordinate in save area
|
|
; SI = old pointer's Y screen coordinate
|
|
; BP = old pointer's X screen coordinate
|
|
; DI = --> new pointer's RECT_DATA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
moved_down:
|
|
|
|
; The screen Y origin of the overlap rectangle is the new rectangle's
|
|
; Y coordinate, or the old rectangle's Y coordinate + |dy|.
|
|
|
|
mov al, bh
|
|
add rdOverlap.rd_ptlScreen.ptl_y, eax
|
|
|
|
; Compute where the new top is. This will be both the top of the new
|
|
; rectangle and the overlap area.
|
|
|
|
; mov al, bh ;BH = |dy|
|
|
add al, dh ;DH = ptbSave.ptb_y
|
|
and al, SAVE_BUFFER_HEIGHT-1 ;CH = sizbMask.sizb_cy
|
|
mov [edi].pd_rd.rd_ptbSave.ptb_y, al
|
|
mov rdOverlap.rd_ptbSave.ptb_y, al
|
|
|
|
; The height of the read and flush buffers is |dy|. The width is
|
|
; just the working width.
|
|
|
|
mov ah, bh
|
|
mov al, cl ;CL = sizbMask.sizb_cx
|
|
mov rdFlushY.rd_sizb, ax
|
|
mov rdReadY.rd_sizb, ax
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
; The data to be flushed will come from the top of the old rectangle
|
|
|
|
mov eax, edx
|
|
mov rdFlushY.rd_ptbSave, dx
|
|
|
|
; The data to be read will go at the old top + sizbMask.sizb_cy
|
|
|
|
add ah, ch
|
|
add al, bl
|
|
and eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
|
|
mov rdReadY.rd_ptbSave, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The Y screen origin of the flush buffer is the old ptlScreen.ptl_y
|
|
|
|
mov rdFlushY.rd_ptlScreen.ptl_y, esi
|
|
|
|
; The height of the overlap rectangle is sizbMask.sizb_cy - |dy|.
|
|
; This is also the Y offset into the work area of the read rectangle.
|
|
; The X offset is zero.
|
|
|
|
mov ah, ch
|
|
sub ah, bh
|
|
mov rdOverlap.rd_sizb.sizb_cy, ah
|
|
xor al, al
|
|
mov rdReadY.rd_ptbWork, ax
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
; The screen X origin of the read rectangle is the new rectangle's X
|
|
; coordinate. The Y coordinate can be computed as the old
|
|
; rectangle's Y coordinate + the save height
|
|
|
|
mov al, ch
|
|
xor ah, ah
|
|
add eax, esi
|
|
|
|
finish_y_overlap:
|
|
mov rdReadY.rd_ptlScreen.ptl_y, eax
|
|
mov eax, [edi].pd_rd.rd_ptlScreen.ptl_x
|
|
mov rdReadY.rd_ptlScreen.ptl_x, eax
|
|
|
|
; The X address of the flush rectangle on the screen is ptlScreen.ptl_x.
|
|
|
|
mov rdFlushY.rd_ptlScreen.ptl_x, ebp
|
|
|
|
; Set the flags to show that there is some form of Y overlap. We want
|
|
; to show that there is some Y rectangle to be read/flushed, and that
|
|
; there is some overlap rectangle to be processed.
|
|
|
|
or WORD PTR fbFlush, ((FB_READ_Y OR FB_OVERLAP) SHL 8) + FB_FLUSH_Y
|
|
|
|
.ERRNZ fbAndRead-fbFlush-1
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; We have computed the seperate X and Y componets of the overlap. If
|
|
; there was both dx and dy, then we have an L shaped area which we'll
|
|
; be reading/writing. In this case, we want to remove the overlapping
|
|
; portion of the L.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
or bl, bl
|
|
jz short processed_y_overlap
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; We have something which looks like one of the following:
|
|
;
|
|
; ---------- ----------
|
|
; | flush | | flush | dy > 0
|
|
; | f | | f |
|
|
; | l ---------- ---------- l | -----
|
|
; | u | | | | | | u | |
|
|
; | s | | | | | | s | limit the "x" rectangles to
|
|
; | h | 1 | r | | r | 2 | h | this height
|
|
; | | | e | | e | | | |
|
|
; ---|------ a | | a ------|--- -----
|
|
; | d | | d | \
|
|
; | read | | read |\ \
|
|
; ---------- ---------- \ \
|
|
; \ \_____ The "x" overlap rectangle
|
|
; \
|
|
; \______ The "y" overlap rectangle
|
|
;
|
|
;
|
|
;
|
|
; ---------- ---------- dy < 0
|
|
; | read | | read |
|
|
; | r | | r |
|
|
; | e ------|--- ---|------ e | -----
|
|
; | a | | | | | | a | |
|
|
; | d | | f | | f | | d | limit the "x" rectangles to
|
|
; | | 3 | l | | l | 4 | | this height
|
|
; | | | u | | u | | | |
|
|
; ---------- s | | s ---------- -----
|
|
; | h | | h |
|
|
; | flush | | flush |
|
|
; ---------- ----------
|
|
;
|
|
;
|
|
; The corners of the L shape are contained in both the X and Y
|
|
; rectangles we just created. We'll remove the overlap from the
|
|
; X rectangles. To do this, we must subtract |dy| from the height
|
|
; stored in the rectangles (which is sizbMask.sizb_cy) and adjust
|
|
; X parameters of either the read or flush rectangles.
|
|
;
|
|
; For cases 1 and 2, we want to adjust X parameters of the flush
|
|
; rectangle. For cases 3 and 4, we want to adjust X parameters
|
|
; of the read rectangle.
|
|
;
|
|
; Currently:
|
|
; BH = dy
|
|
; BL = dx
|
|
; CH = buffer height
|
|
; CL = buffer width
|
|
; DH = old pointer's Y coordinate in save area
|
|
; DL = old pointer's X coordinate in save area
|
|
; SI = old pointer's Y screen coordinate
|
|
; BP = old pointer's X screen coordinate
|
|
; DI = --> new pointer's RECT_DATA
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, bh
|
|
mov ebx, offset FLAT:rdFlushX ;Assume cases 1 and 2
|
|
or al, al
|
|
jns short @F
|
|
mov ebx, offset FLAT:rdReadX ;Its cases 3 and 4
|
|
neg al ;|dy|
|
|
add [ebx].rd_ptbWork.ptb_y, al;Move down in the work area too!
|
|
@@:
|
|
mov cl, [ebx].rd_ptbSave.ptb_y
|
|
add cl, al
|
|
and cl, SAVE_BUFFER_HEIGHT-1
|
|
mov [ebx].rd_ptbSave.ptb_y, cl
|
|
movsx eax, al
|
|
|
|
.ERRNZ (SAVE_BUFFER_HEIGHT-1) AND 80h
|
|
|
|
add [ebx].rd_ptlScreen.ptl_y, eax
|
|
neg al
|
|
add al, ch ;sizbMask.sizb_cy - |dy|
|
|
mov rdFlushX.rd_sizb.sizb_cy, al
|
|
mov rdReadX.rd_sizb.sizb_cy, al
|
|
|
|
processed_y_overlap:
|
|
compute_rects_exit:
|
|
|
|
pop ebp
|
|
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; clip_rects
|
|
;
|
|
; This routine clips the rectangles computed by compute_rects.
|
|
;
|
|
; Entry:
|
|
; None
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; do_clipping
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_rects:
|
|
|
|
mov esi, ppdOld ;--> old POINTER_DATA structure
|
|
mov dl, [esi].pd_fb
|
|
test dl, PD_CLIPPED ;Won't be set if PD_VALID isn't set
|
|
jz short old_been_clipped
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The old pointer needs some form of clipping. This can affect either
|
|
; the old pointer's rectangle or rdFlushX and rdFlushY. Since the old
|
|
; pointer's rectangle will be discarded after it is restored, we don't
|
|
; care if we write over it's contents.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov edi, esi ;EDI --> rectangle to clip
|
|
mov bl, fbFlush ;fbFlush tells us which rects to use
|
|
mov bh, FB_OLD_PTR
|
|
test bl, bh
|
|
jnz short call_do_clip ;Only have to clip old pointer's rect
|
|
mov edi, offset FLAT:rdFlushX
|
|
mov bh, FB_FLUSH_X
|
|
test bl, bh
|
|
jz short @F
|
|
call do_clipping
|
|
@@:
|
|
mov edi, offset FLAT:rdFlushY
|
|
mov bh, FB_FLUSH_Y
|
|
test bl, bh
|
|
jz short @F
|
|
call_do_clip:
|
|
call do_clipping
|
|
@@:
|
|
mov fbFlush, bl
|
|
|
|
mov edi, offset FLAT:rdOverlap
|
|
mov bl, fbAndRead
|
|
mov bh, FB_OVERLAP
|
|
test bl, bh
|
|
jz short @F
|
|
call do_clipping
|
|
mov fbAndRead, bl
|
|
@@:
|
|
old_been_clipped:
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The old pointer rectangle has been clipped. Now see about clipping
|
|
; the new pointer rectangle.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi, ppdNew ;--> new POINTER_DATA structure
|
|
mov dl, [esi].pd_fb
|
|
test dl, PD_CLIPPED ;Won't be set if PD_VALID isn't set
|
|
jz short new_been_clipped
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The new rectangle structure needs to be clipped. This presents a
|
|
; minor problem in that we don't want to destroy the screen X,Y and
|
|
; buffer X,Y of the pointer's POINTER_DATA structure. What we'll do
|
|
; instead is to copy it to the rdWork structure and update it there.
|
|
; We'll also set up to XOR this to the screen instead of the
|
|
; POINTER_DATA structure.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
lodsw
|
|
mov rdWork.rd_ptbSave, ax
|
|
|
|
.ERRNZ rd_ptbSave
|
|
.ERRNZ (SIZE POINTB) - 2
|
|
|
|
lodsd
|
|
mov rdWork.rd_ptlScreen.ptl_x, eax
|
|
|
|
.ERRNZ rd_ptlScreen-rd_ptbSave-2
|
|
.ERRNZ ptl_x
|
|
|
|
lodsd
|
|
mov rdWork.rd_ptlScreen.ptl_y, eax
|
|
|
|
.ERRNZ ptl_y-ptl_x-4
|
|
|
|
lodsw
|
|
mov rdWork.rd_sizb, ax
|
|
|
|
.ERRNZ (SIZE SIZEB) - 2
|
|
|
|
lodsw
|
|
mov rdWork.rd_ptbWork, ax
|
|
|
|
.ERRNZ (SIZE POINTB) - 2
|
|
|
|
sub esi,SIZE RECT_DATA ;--> to start of POINTER_DATA
|
|
|
|
.ERRNZ (rd_ptbWork+2)-(SIZE RECT_DATA)
|
|
|
|
; Perform the clipping for the work area. We know that some part of the
|
|
; work area exists, else we wouldn't be here with a valid rectangle.
|
|
; If FB_NEW_PTR is set in fbAndRead, then we want to replace it with
|
|
; FB_WORK_RECT, else we'll want to process any overlap rectangles.
|
|
|
|
mov edi,offset FLAT:rdWork
|
|
call do_clipping
|
|
mov bh,FB_WORK_RECT
|
|
mov fbXor,bh
|
|
mov bl,fbAndRead
|
|
mov fbAndRead,bh ;assume only work rect to and/read
|
|
test bl,FB_NEW_PTR
|
|
jnz short new_been_clipped
|
|
|
|
mov edi, offset FLAT:rdReadX
|
|
mov bh, FB_READ_X
|
|
test bl, bh
|
|
jz short @F
|
|
call do_clipping
|
|
@@:
|
|
mov edi, offset FLAT:rdReadY
|
|
mov bh, FB_READ_Y
|
|
test bl, bh
|
|
jz short @F
|
|
call do_clipping
|
|
@@:
|
|
mov fbAndRead, bl
|
|
|
|
new_been_clipped:
|
|
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; do_clipping
|
|
;
|
|
; This routine performs the actual clipping of a rectangle using the
|
|
; passed POINTER_DATA and RECT_DATA structures.
|
|
;
|
|
; Entry:
|
|
; BL = flag byte
|
|
; BH = bit to clear in BL if rectangle is invisible
|
|
; DL = pd_fb for [si]
|
|
; SI --> POINTER_DATA structure
|
|
; DI --> RECT_DATA structure
|
|
; Returns:
|
|
; BL updated
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; DX,SI,DI,BP
|
|
; Registers Destroyed:
|
|
; AX,BH,CX
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
|
|
do_clipping:
|
|
|
|
.ERRNZ pd_rd ;Must be at offset 0
|
|
|
|
xor eax, eax
|
|
test dl, PD_CLIP_BOTTOM OR PD_CLIP_TOP
|
|
jz short y_clipping_done
|
|
mov ecx, [edi].rd_ptlScreen.ptl_y
|
|
js short clip_on_bottom_eh?
|
|
|
|
.ERRNZ PD_CLIP_BOTTOM-10000000b
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Top clipping may have to be performed for this rectangle.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_on_top:
|
|
neg ecx ;If it was negative, then must clip
|
|
jle short y_clipping_done ;Was positive, no clipping needed
|
|
sub [edi].rd_sizb.sizb_cy, cl ;Compute new height
|
|
jle short clear_visible_bit ;Clipped away, nothing visible
|
|
add [edi].rd_ptbWork.ptb_y, cl ;Move down in work area
|
|
add cl, [edi].rd_ptbSave.ptb_y ;Move down in save area
|
|
and cl, SAVE_BUFFER_HEIGHT-1
|
|
mov [edi].rd_ptbSave.ptb_y, cl
|
|
mov [edi].rd_ptlScreen.ptl_y, eax
|
|
jmp short finish_y_clipping
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Bottom clipping may have to be performed for this rectangle.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_on_bottom_eh?:
|
|
mov al, [edi].rd_sizb.sizb_cy
|
|
add ecx, eax
|
|
sub ecx, cyScreen
|
|
jle short finish_y_clipping ;EAX = amount to clip if positive
|
|
sub al, cl ;Compute new height
|
|
jle short clear_visible_bit ;Clipped away, nothing visible
|
|
mov [edi].rd_sizb.sizb_cy, al
|
|
finish_y_clipping:
|
|
xor eax, eax
|
|
y_clipping_done:
|
|
|
|
|
|
test dl, PD_CLIP_LEFT OR PD_CLIP_RIGHT
|
|
jz short x_clipping_done
|
|
mov ecx, [edi].rd_ptlScreen.ptl_x
|
|
test dl, PD_CLIP_RIGHT
|
|
jnz short clip_on_rhs
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; lhs clipping may have to be performed for this rectangle.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_on_lhs:
|
|
neg ecx ;If it was negative, then must clip
|
|
jle short x_clipping_done ;Was positive, no clipping needed
|
|
sub [edi].rd_sizb.sizb_cx, cl ;Compute new width
|
|
jle short clear_visible_bit ;Clipped away, nothing visible
|
|
add [edi].rd_ptbWork.ptb_x, cl;Move right in work area
|
|
add cl, [edi].rd_ptbSave.ptb_x;Move right in save area
|
|
and cl, SAVE_BUFFER_WIDTH-1
|
|
mov [edi].rd_ptbSave.ptb_x, cl
|
|
mov [edi].rd_ptlScreen.ptl_x, eax
|
|
jmp short x_clipping_done
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; rhs clipping may have to be performed for this rectangle.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
clip_on_rhs:
|
|
mov al,[edi].rd_sizb.sizb_cx
|
|
add ecx,eax
|
|
sub ecx,lNextScan
|
|
jle short x_clipping_done ;EAX = amount to clip if positive
|
|
sub al,cl ;Compute new height
|
|
jle short clear_visible_bit ;Clipped away, nothing visible
|
|
mov [edi].rd_sizb.sizb_cx, al
|
|
x_clipping_done:
|
|
xor bh,bh ;0 to cancel following XOR
|
|
|
|
clear_visible_bit:
|
|
xor bl,bh ;Update visible bit
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; xor_to_screen
|
|
;
|
|
; The work area is XORed with the XOR mask and placed on the screen
|
|
;
|
|
; Entry:
|
|
; AL = fbXor
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ pd_rd ;Must be at offset 0
|
|
|
|
xor_to_screen:
|
|
xor ebx, ebx ;Zero will be useful soon
|
|
shr al, 1 ;Set 'C' to FB_WORK_RECT bit
|
|
|
|
.ERRNZ FB_WORK_RECT-00000001b
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Program the EGA for XOR mode. This will be done using M_PROC_WRITE,
|
|
; M_DATA_READ, DR_XOR, and setting GRAF_BIT_MASK to FF. The normal
|
|
; sequence of events will have left the bitmask register with 00h and
|
|
; the mode register in AND mode.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov dx, EGA_BASE + GRAF_ADDR
|
|
mov ax, 0FF00h + GRAF_BIT_MASK
|
|
out dx, ax ;Enable all bits
|
|
mov ax, DR_XOR SHL 8 + GRAF_DATA_ROT
|
|
out dx, ax
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the offset from the start of the work area and the XOR mask
|
|
; (its the same value). If we're to use the new pointer's rectangle,
|
|
; then this offset is zero.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi,ppdNew ;assume new pointer is in use
|
|
jnc short have_xor_mask_offset ;EBX = 0 is offset
|
|
|
|
.ERRNZ FB_WORK_RECT-00000001b
|
|
.ERRE FB_NEW_PTR-00000001b
|
|
|
|
mov esi,offset FLAT:rdWork ;The work area (we be clipping)
|
|
movzx eax,WORD PTR [esi].rd_ptbWork ;Get origin in work area
|
|
xchg ah, bl ;BX = ptbWork.ptb_y, AX = ptbWork.ptb_x
|
|
add eax,ebx ;*1 + X component
|
|
add ebx,ebx ;*2
|
|
add ebx,ebx ;*4
|
|
add ebx,eax ;*5 + X = start from work/mask
|
|
|
|
.ERRNZ WORK_WIDTH-5
|
|
|
|
have_xor_mask_offset:
|
|
|
|
|
|
; Map the proper bank into the destination window for the top destination
|
|
; scan line.
|
|
|
|
mov edi,pdsurf
|
|
mov edx,[esi].rd_ptlScreen.ptl_y
|
|
mov ulCurrentTopScan,edx ;remember where the top dest scan is
|
|
cmp edx,[edi].dsurf_rcl2WindowClipD.yTop ;is xor top less than
|
|
; current dest bank?
|
|
jl short xts_map_init_bank ;yes, map in proper bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipD.yBottom ;xor top greater than
|
|
; current dest bank?
|
|
jl short xts_init_bank_mapped ;no, proper bank already mapped
|
|
xts_map_init_bank:
|
|
|
|
; Map bank containing the top destination (screen) scan line into dest window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyTop,MapDestBank>
|
|
|
|
xts_init_bank_mapped:
|
|
|
|
|
|
; Map the cursor bank into the source window.
|
|
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
|
|
; current source bank?
|
|
jl short xts_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
|
|
; than current source
|
|
; bank?
|
|
jl short xts_ptr_bank_mapped ;no, proper bank already mapped
|
|
xts_map_ptr_bank:
|
|
|
|
; Map cursor work bank into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyBottom,MapSourceBank>
|
|
|
|
xts_ptr_bank_mapped:
|
|
|
|
|
|
; Compute the screen address of this rectangle and get its size
|
|
|
|
mov ecx,[edi].dsurf_pvBitmapStart2WindowD ;start of screen bitmap
|
|
mov edi,lNextScan ;width of screen bitmap
|
|
imul edi,[esi].rd_ptlScreen.ptl_y ;offset of dest start in screen
|
|
add edi,[esi].rd_ptlScreen.ptl_x ; buffer
|
|
add edi,ecx ;virtual address of dest start
|
|
|
|
mov cx,[esi].rd_sizb ;CH = scans to copy
|
|
; CL = bytes across to copy
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; To save incrementing the work area pointer (BX), subtract the XOR
|
|
; mask pointer off of it. Then use [BX][SI] for addressing into the
|
|
; XOR mask. As SI is incremented, BX will effectively be incremented.
|
|
; We could not do this if the XOR mask and the work area were different
|
|
; widths.
|
|
;
|
|
; Finish computing the pointer to the XOR mask and the delta from the
|
|
; XOR mask to the work area.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi,pAndXor ;set address of XOR mask
|
|
lea esi,[esi][ebx][base_xor_masks-base_and_masks]
|
|
add ebx,pPtrWork ;start src offset in bitmap
|
|
mov eax,pdsurf
|
|
add ebx,[eax].dsurf_pvBitmapStart2WindowS ;start src virtual addr
|
|
sub ebx,esi ;fudge back so we get away with one
|
|
; increment
|
|
|
|
; Calculate the number of scans we'll do in this bank.
|
|
|
|
mov edx,[eax].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the initial bank
|
|
sub eax,eax
|
|
mov al,ch ;total # of scans to copy
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub ch,al ;count this bank's scans off total
|
|
mov byte ptr cjTotalScans,ch ;remember # of scans after this bank
|
|
mov ch,al ;# of scans to do in this bank
|
|
|
|
; Compute the delta to the start of the next scanline of the XOR mask
|
|
; and the work area, and the next scan of the screen
|
|
|
|
sub eax,eax
|
|
mov al,cl ;width to copy in bytes
|
|
mov edx,WORK_WIDTH
|
|
sub edx,eax ;offset from end of one source scan to
|
|
mov ulNextSrcScan,edx ; start of next
|
|
add edx,lNextScan ;offset from end of one dest scan to
|
|
sub edx,WORK_WIDTH ; start of next
|
|
|
|
lea eax,[eax*4]
|
|
neg eax
|
|
add eax,offset FLAT:xor_to_screen_width_0
|
|
|
|
push ebp ;remember stack frame pointer
|
|
mov ebp,ulNextSrcScan ;offset to next XOR scan
|
|
jmp eax
|
|
|
|
.ERRNZ WORK_WIDTH-5
|
|
;-----------------------------------------------------------------------;
|
|
; Register usage for the loop will be:
|
|
;
|
|
; AX = loop starting address
|
|
; BX = offset off [si] to the work area
|
|
; CH = height
|
|
; DX = delta to next scan of the destination
|
|
; SI --> XOR mask
|
|
; DI --> Destination
|
|
; BP = offset to next byte of XOR mask, next scan of work area
|
|
;-----------------------------------------------------------------------;
|
|
|
|
xor_to_screen_width_5:
|
|
cmp al, [ebx][esi] ;Load latches from work area
|
|
movsb ;XOR to the screen
|
|
xor_to_screen_width_4:
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
xor_to_screen_width_3:
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
xor_to_screen_width_2:
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
xor_to_screen_width_1:
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
xor_to_screen_width_0:
|
|
|
|
.ERRNZ xor_to_screen_width_0-xor_to_screen_width_1-4
|
|
.ERRNZ xor_to_screen_width_1-xor_to_screen_width_2-4
|
|
.ERRNZ xor_to_screen_width_2-xor_to_screen_width_3-4
|
|
.ERRNZ xor_to_screen_width_3-xor_to_screen_width_4-4
|
|
.ERRNZ xor_to_screen_width_4-xor_to_screen_width_5-4
|
|
|
|
add esi, ebp ;--> next scan's XOR mask, work addr
|
|
add edi, edx ;--> next scan's destination
|
|
dec ch ;count down lines in this bank
|
|
jz short @F ;no more lines in this bank
|
|
jmp eax ;do the next line in this bank
|
|
|
|
@@: ;done with bank
|
|
pop ebp ;retrieve stack frame pointer
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
|
|
jz short xts_done ;no, we're done
|
|
;advance to next dest bank and continue
|
|
; XORing
|
|
push eax ;preserve entry vector
|
|
push edx ;preserve dest next scan
|
|
mov eax,pdsurf
|
|
sub edi,[eax].dsurf_pvBitmapStart2WindowD
|
|
;calculate the destination offset
|
|
; within the bitmap, because the start
|
|
; address is about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [eax].dsurf_pfnBankControl2Window>, \
|
|
<eax,edx,JustifyTop,MapDestBank> ;map in the next dest bank
|
|
|
|
mov eax,pdsurf
|
|
add edi,[eax].dsurf_pvBitmapStart2WindowD
|
|
;add back in the bitmap start address
|
|
; to yield the virtual dest address
|
|
mov edx,[eax].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
mov ch,al ;# of scans to do in this bank
|
|
|
|
pop edx ;restore dest next scan
|
|
pop eax ;restore entry vector
|
|
|
|
push ebp ;remember stack frame pointer
|
|
mov ebp,ulNextSrcScan ;offset to next XOR scan
|
|
jmp eax ;do the next block of scans
|
|
|
|
xts_done:
|
|
PLAIN_RET
|
|
|
|
page
|
|
;--------------------------Private-Routine------------------------------;
|
|
; color_pointer_to_screen
|
|
;
|
|
; The color pointer is output to the screen using AND/XOR/COLOR masks.
|
|
;
|
|
; Entry:
|
|
; None
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
color_pointer_to_screen:
|
|
|
|
.ERRNZ pd_rd ;Must be at offset 0
|
|
|
|
; Set up variables that don't change from plane to plane in the outer loop
|
|
|
|
mov esi,ppdNew
|
|
test fbXor,FB_WORK_RECT
|
|
jz short cps_have_pointer_rect
|
|
mov esi,offset FLAT:rdWork ;the work area (we be clipping)
|
|
cps_have_pointer_rect:
|
|
mov prclSource,esi
|
|
|
|
; Map the proper bank into the destination window for the top destination
|
|
; scan line.
|
|
|
|
mov ebx,pdsurf
|
|
mov edx,[esi].rd_ptlScreen.ptl_y
|
|
mov ulCurrentTopScan,edx ;remember where the top dest scan is
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is copy top less than
|
|
; current dest bank?
|
|
jl short cpts_map_init_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;copy top greater than
|
|
; current dest bank?
|
|
jl short cpts_init_bank_mapped ;no, proper bank already mapped
|
|
cpts_map_init_bank:
|
|
|
|
; Map bank containing the top destination (screen) scan line into dest window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyTop,MapDestBank>
|
|
|
|
cpts_init_bank_mapped:
|
|
|
|
|
|
; Map the cursor bank into the source window.
|
|
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
|
|
; current source bank?
|
|
jl short cpts_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
|
|
; than current source
|
|
; bank?
|
|
jl short cpts_ptr_bank_mapped ;no, proper bank already mapped
|
|
cpts_map_ptr_bank:
|
|
|
|
; Map cursor work bank into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyBottom,MapSourceBank>
|
|
|
|
cpts_ptr_bank_mapped:
|
|
|
|
|
|
; Offset to next screen scan, minus the width of the work area, will
|
|
; come in handy in the inner loop.
|
|
|
|
mov eax,lNextScan ;width of screen bitmap
|
|
mov edi,eax ;set aside for computing the screen address
|
|
sub eax,WORK_WIDTH
|
|
mov ulScanMinusWorkWidth,eax
|
|
|
|
; Compute the screen address of the rectangle in this bank
|
|
|
|
imul edi,[esi].rd_ptlScreen.ptl_y ;offset of dest start in screen
|
|
add edi,[esi].rd_ptlScreen.ptl_x ; buffer
|
|
add edi,[ebx].dsurf_pvBitmapStart2WindowD ;virtual address of dest
|
|
; start
|
|
mov pDest,edi
|
|
|
|
; Remember the save source point.
|
|
|
|
sub eax,eax
|
|
mov ax,word ptr [esi].rd_ptbSave
|
|
mov jSaveSourceXY,eax
|
|
mov byte ptr jNextSaveSourceY,ah
|
|
|
|
|
|
; Remember the work source point.
|
|
|
|
mov ax,word ptr [esi].rd_ptbWork
|
|
mov jWorkSourceXY,eax
|
|
mov byte ptr jNextWorkSourceY,ah
|
|
|
|
|
|
; Calculate the number of scans we'll do in this bank.
|
|
|
|
mov edx,[ebx].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the initial bank
|
|
mov ch,byte ptr [esi].rd_sizb+1 ;total # of scans to copy
|
|
sub eax,eax
|
|
mov al,ch
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
add byte ptr jNextSaveSourceY,al ;top save source scan for next bank
|
|
add byte ptr jNextWorkSourceY,al ;top work source scan for next bank
|
|
sub ch,al ;count this bank's scans off total
|
|
mov byte ptr cjTotalScans,ch ;remember # of scans after this bank
|
|
mov byte ptr jScansInBank,al ;# of scans to do in this bank
|
|
|
|
; Set the virtual address of the save area
|
|
|
|
mov eax,[ebx].dsurf_pvBitmapStart2WindowS ;start of source bitmap
|
|
add eax,pPtrSave ;virtual address of save area
|
|
mov pWorkingSave,eax
|
|
|
|
; Loop through banks that this cursor spans
|
|
|
|
cpts_bank_loop:
|
|
|
|
; Initial plane is plane 3
|
|
|
|
mov iPlaneMask,MM_C3
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Program the VGA for SET mode. This will be done using M_PROC_WRITE,
|
|
; M_DATA_READ, DR_SET, and setting GRAF_BIT_MASK to FF. The normal
|
|
; sequence of events will have left the bitmask register with 00h and
|
|
; the mode register in AND mode.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov dx,EGA_BASE + GRAF_ADDR
|
|
mov ax,0FF00h + GRAF_BIT_MASK
|
|
out dx,ax ;enable all bits
|
|
mov ax,DR_SET SHL 8 + GRAF_DATA_ROT
|
|
out dx,ax
|
|
mov al,GRAF_READ_MAP
|
|
out dx,al ;leave the GC Index pointing to the Read Map reg
|
|
|
|
cps_do_next_plane:
|
|
|
|
; Set write plane enable register to the ONE plane we will alter
|
|
|
|
mov al,byte ptr iPlaneMask ;set Map Mask
|
|
mov dx,EGA_BASE + SEQ_DATA
|
|
out dx,al
|
|
|
|
; Set read plane to plane to read from
|
|
|
|
shr al,1 ;map plane into ReadMask
|
|
cmp al,100b ;set Carry if not C3 (plane 3)
|
|
adc al,-1 ;sub 1 only if C3
|
|
mov dl,GRAF_DATA
|
|
out dx,al
|
|
|
|
mov esi,prclSource ;point to source rect
|
|
mov edi,pDest ;point to initial dest byte
|
|
|
|
mov eax,jSaveSourceXY
|
|
mov edx,jWorkSourceXY
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
mov cl,byte ptr [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
mov bl,al ;see if save area is contiguous
|
|
add bl,cl
|
|
sub bl,SAVE_BUFFER_WIDTH ;BL = is overhang
|
|
jle short call_cps_do_a_pass ;no overhang
|
|
|
|
sub cl,bl ;set X extent for pass 1
|
|
mov bh,cl ;need it for pass 2
|
|
mov ch,byte ptr jScansInBank ;# of scans to do in this bank
|
|
push ebx
|
|
call cps_do_a_pass ;process first half
|
|
pop ebx
|
|
|
|
mov esi,prclSource ;point to source rect
|
|
mov edi,pDest ;point to initial dest byte
|
|
|
|
mov eax,jSaveSourceXY
|
|
mov edx,jWorkSourceXY
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
mov cl,byte ptr [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
add dl,bh ;move right in work area
|
|
mov cl,bl ;set new extent
|
|
xor al,al ;X origin in save area is 0
|
|
movzx ebx,bh ;move right in destination area
|
|
add edi,ebx
|
|
|
|
call_cps_do_a_pass:
|
|
mov ch,byte ptr jScansInBank ;# of scans to do in this bank
|
|
call cps_do_a_pass ;process second half (or the whole
|
|
; color cursor, if no overhang)
|
|
|
|
shr iPlaneMask,1
|
|
jnc short cps_do_next_plane
|
|
|
|
.ERRNZ MM_C0-00000001b
|
|
.ERRNZ MM_C1-00000010b
|
|
.ERRNZ MM_C2-00000100b
|
|
.ERRNZ MM_C3-00001000b
|
|
|
|
;we've done all planes in this bank
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
|
|
jz short cpts_done ;no, we're done
|
|
;advance to next dest bank and continue
|
|
; XORing
|
|
|
|
; Advance the source Y coordinates to match the bank advance we're about to do.
|
|
|
|
mov al,byte ptr jNextSaveSourceY
|
|
mov byte ptr jSaveSourceXY+1,al
|
|
mov al,byte ptr jNextWorkSourceY
|
|
mov byte ptr jWorkSourceXY+1,al
|
|
|
|
; Advance to the next dest bank.
|
|
|
|
mov ebx,pdsurf
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyTop,MapDestBank> ;map in the next dest bank
|
|
|
|
; Compute the screen start address of the rectangle in this bank
|
|
|
|
mov esi,prclSource ;point to source rect
|
|
mov edi,lNextScan ;width of screen bitmap
|
|
imul edi,ulCurrentTopScan ;offset of dest start in screen
|
|
add edi,[esi].rd_ptlScreen.ptl_x ; buffer
|
|
add edi,[ebx].dsurf_pvBitmapStart2WindowD ;virtual address of dest
|
|
; start
|
|
mov pDest,edi
|
|
|
|
mov edx,[ebx].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
add byte ptr jNextSaveSourceY,al ;top save source scan for next bank
|
|
add byte ptr jNextWorkSourceY,al ;top work source scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
mov byte ptr jScansInBank,al ;# of scans to do in this bank
|
|
|
|
jmp cpts_bank_loop ;do the next block of scans
|
|
|
|
cpts_done:
|
|
PLAIN_RET
|
|
|
|
page
|
|
;--------------------------Private-Routine------------------------------;
|
|
; cps_do_a_pass
|
|
;
|
|
; Output one plane of the color pointer to the screen using
|
|
; AND/XOR/COLOR masks. Does not handle bank spanning; that is taken care
|
|
; of in color_pointer_to_screen.
|
|
;
|
|
; Entry:
|
|
; AH = ptbSave.ptb_y, AL = ptbSave.ptb_x
|
|
; DH = ptbWork.ptb_y, DL = ptbWork.ptb_x
|
|
; CL = x bytes to process
|
|
; CH = y scans to process
|
|
; EDI --> Destination (screen area)
|
|
; EBP = stack frame
|
|
; VGA set up to enable writes to proper plane
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; EBP
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cps_do_a_pass:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the offset within the save area. Note that this is relative
|
|
; to screen_buf.
|
|
; AH = ptbSave.ptb_y, AL = ptbSave.ptb_x
|
|
;-----------------------------------------------------------------------;
|
|
|
|
shl ah,3
|
|
add al,ah ;y * 8 + x
|
|
xor ah,ah
|
|
cwde
|
|
mov ulOffsetSave,eax
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
.ERRNZ SAVE_BUFFER_HEIGHT-32
|
|
|
|
mov esi,pWorkingSave ;point to the save area
|
|
add esi,eax ;ESI --> start address in save area
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the offset within the AND/XOR masks.
|
|
; DH = ptbWork.ptb_y, DL = ptbWork.ptb_x
|
|
;-----------------------------------------------------------------------;
|
|
|
|
xor ebx,ebx
|
|
xchg dh,bl
|
|
add edx,ebx ;y * 1 + x
|
|
add ebx,ebx ;y * 2
|
|
add ebx,ebx ;y * 4
|
|
add ebx,edx ;y * 5 + x
|
|
mov ulOffsetMask,ebx
|
|
add ebx,pAndXor ;EBX --> start address of AND mask
|
|
sub ebx,edi ;make EBX relative to EDI
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the delta to the start of the next scanline of destination
|
|
; screen area
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, cl
|
|
movsx eax, al
|
|
mov edx,lNextScan
|
|
sub edx,eax
|
|
mov ulDeltaScreen,edx ;delta to next scan of screen area
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Calculate EDX = jump table address
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov edx,color_to_screen_entry_table[eax*4]
|
|
|
|
.ERRNZ WORK_WIDTH-5
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the offset within the COLOR mask.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
push ebp ;need an extra register
|
|
mov al,byte ptr iPlaneMask ;AL --> iPlaneMask
|
|
mov ebp,ulOffsetMask ;EBP --> usoffset_mask
|
|
add ebp,pColor ;EBP --> start address of COLOR mask
|
|
shr al,1
|
|
jz short @F
|
|
add ebp,MASK_LENGTH
|
|
shr al,1
|
|
jz short @F
|
|
add ebp,MASK_LENGTH
|
|
shr al,1
|
|
jz short @F
|
|
add ebp,MASK_LENGTH
|
|
@@:
|
|
sub ebp,edi ;make BP relative
|
|
|
|
jmp edx
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Register usage for the loop will be:
|
|
;
|
|
; EBX = offset off EDI to the AND mask
|
|
; CH = height
|
|
; EDX = loop starting address
|
|
; ESI --> Source (save area)
|
|
; EDI --> Destination (screen area)
|
|
; EBP = offset off EDI to the COLOR mask
|
|
;-----------------------------------------------------------------------;
|
|
|
|
color_to_screen_width_5::
|
|
lodsb
|
|
and al,[ebx][edi]
|
|
xor al,[ebp][edi]
|
|
stosb
|
|
color_to_screen_width_4::
|
|
lodsb
|
|
and al,[ebx][edi]
|
|
xor al,[ebp][edi]
|
|
stosb
|
|
color_to_screen_width_3::
|
|
lodsb
|
|
and al,[ebx][edi]
|
|
xor al,[ebp][edi]
|
|
stosb
|
|
color_to_screen_width_2::
|
|
lodsb
|
|
and al,[ebx][edi]
|
|
xor al,[ebp][edi]
|
|
stosb
|
|
color_to_screen_width_1::
|
|
lodsb
|
|
and al,[ebx][edi]
|
|
xor al,[ebp][edi]
|
|
stosb
|
|
color_to_screen_width_0::
|
|
|
|
mov eax,ebp ;EAX --> next scan's COLOR mask
|
|
pop ebp
|
|
sub eax,ulScanMinusWorkWidth
|
|
|
|
; WE HAVE NO SPARE REGISTERS HERE
|
|
|
|
push eax
|
|
mov eax,ulOffsetSave
|
|
add al,SAVE_BUFFER_WIDTH ;Take into account wrap around
|
|
mov esi,pWorkingSave ;point to the save area
|
|
add esi,eax ;ESI --> next scan's save area
|
|
mov ulOffsetSave,eax
|
|
pop eax
|
|
|
|
add edi,ulDeltaScreen ;EDI --> next scan's screen area
|
|
sub ebx,ulScanMinusWorkWidth
|
|
;EBX --> next scan's AND mask
|
|
dec ch
|
|
jz cps_exit
|
|
|
|
push ebp
|
|
mov ebp,eax ;EBP --> next scan's COLOR mask
|
|
jmp edx ;do the next scan line
|
|
|
|
cps_exit:
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; and_into_work
|
|
;
|
|
; All rectangles which are to be ANDed into the work area are
|
|
; dispatched to the routine which will do the actual ANDing.
|
|
;
|
|
; Entry:
|
|
; AL = fbAndRead
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; and_from_screen
|
|
; and_from_save
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
and_into_work:
|
|
|
|
push ebp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Program the EGA for AND mode. This will be done using M_PROC_WRITE,
|
|
; M_DATA_READ, DR_AND, and setting GRAF_BIT_MASK to FF. All but setting
|
|
; DR_AND was set by save_hw_regs. All planes were also enabled for
|
|
; writing by save_hw_regs.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ecx, eax
|
|
mov dx, EGA_BASE + GRAF_ADDR
|
|
mov ax, DR_AND SHL 8 + GRAF_DATA_ROT
|
|
out dx, ax
|
|
mov eax, ecx
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; If FB_NEW_PTR or FB_WORK_AREA is set, then we only have a single
|
|
; rectangle to deal with, located on the screen.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi, ppdNew
|
|
test al, FB_NEW_PTR
|
|
jnz short aiw_source_is_screen
|
|
mov esi, offset FLAT:rdWork
|
|
test al, FB_WORK_RECT
|
|
jnz short aiw_source_is_screen
|
|
|
|
; Some combination of FB_READ_X, FB_READ_Y, FB_OVERLAP exists
|
|
|
|
test al, FB_READ_Y
|
|
jz short @F
|
|
mov esi, offset FLAT:rdReadY
|
|
call and_from_screen
|
|
mov al, fbAndRead
|
|
@@:
|
|
|
|
test al, FB_READ_X
|
|
jz short @F
|
|
mov esi, offset FLAT:rdReadX
|
|
aiw_source_is_screen:
|
|
call and_from_screen
|
|
mov al, fbAndRead
|
|
@@:
|
|
|
|
test al, FB_OVERLAP
|
|
jz short @F
|
|
mov esi, offset FLAT:rdOverlap
|
|
call and_from_save
|
|
@@:
|
|
|
|
pop ebp
|
|
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; and_from_screen
|
|
;
|
|
; The screen is ANDed with the AND mask and placed into the work area
|
|
;
|
|
; Entry:
|
|
; ESI --> RECT_DATA structure to use
|
|
; EGA programmed for AND mode
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,FLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
and_from_screen:
|
|
|
|
.ERRNZ pd_rd ;Must be at offset 0
|
|
|
|
mov eax,lNextScan
|
|
sub eax,WORK_WIDTH
|
|
mov ulNextSrcScan,eax ;set the source advance offset
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Map in the source and destination banks.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
; Map the proper bank into the source window for the top source scan line.
|
|
|
|
mov edi,pdsurf
|
|
mov edx,[esi].rd_ptlScreen.ptl_y
|
|
mov ulCurrentTopScan,edx ;remember where the top source scan is
|
|
cmp edx,[edi].dsurf_rcl2WindowClipS.yTop ;is AND top less than
|
|
; current source bank?
|
|
jl short afscr_map_init_bank ;yes, map in proper bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipS.yBottom ;AND top greater than
|
|
; current source bank?
|
|
jl short afscr_init_bank_mapped ;no, proper bank already mapped
|
|
afscr_map_init_bank:
|
|
|
|
; Map bank containing the top destination (screen) scan line into dest window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyTop,MapSourceBank>
|
|
|
|
afscr_init_bank_mapped:
|
|
|
|
|
|
; Map the cursor bank into the destination window.
|
|
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipD.yTop ;is cursor scan less than
|
|
; current dest bank?
|
|
jl short afscr_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[edi].dsurf_rcl2WindowClipD.yBottom ;cursor scan greater
|
|
; than current dest
|
|
; bank?
|
|
jl short afscr_ptr_bank_mapped ;no, proper bank already mapped
|
|
afscr_map_ptr_bank:
|
|
|
|
; Map cursor work bank into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyBottom,MapDestBank>
|
|
|
|
afscr_ptr_bank_mapped:
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the screen address of this rectangle and get its size
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ebx,lNextScan
|
|
imul ebx,[esi].rd_ptlScreen.ptl_y
|
|
add ebx,[esi].rd_ptlScreen.ptl_x ;start source offset in bitmap
|
|
movzx ecx,WORD PTR [esi].rd_sizb ;CH = scans to copy
|
|
; CL = bytes across to copy
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Compute the offset from the start of the work area and the AND mask
|
|
; (it's the same value).
|
|
;-----------------------------------------------------------------------;
|
|
|
|
xor eax,eax
|
|
movzx edx,WORD PTR [esi].rd_ptbWork ;Get origin in work area
|
|
xchg al,dh ;AX = ptbWork.ptb_y, DX = ptbWork.ptb_x
|
|
add edx,eax ;*1 + X component
|
|
add eax,eax ;*2
|
|
add eax,eax ;*4
|
|
add eax,edx ;*5 + X = start from work/mask
|
|
mov edi,eax
|
|
|
|
.ERRNZ WORK_WIDTH-5
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; To save incrementing the source pointer (BX), subtract the AND
|
|
; mask pointer off of it. Then use [BX][SI] for addressing into the
|
|
; source. As SI is incremented, BX will effectively be incremented.
|
|
;
|
|
; The source pointer will have to be adjusted by lNextScan-sizb_cx.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi,pAndXor ;Set address of AND mask
|
|
add esi,edi
|
|
add edi,pPtrWork ;start dest offset in bitmap
|
|
mov eax,pdsurf
|
|
add edi,[eax].dsurf_pvBitmapStart2WindowD ;start dest virtual addr
|
|
add ebx,[eax].dsurf_pvBitmapStart2WindowS ;start src virtual addr
|
|
sub ebx,esi ;fudge back so we get away with one
|
|
; increment
|
|
|
|
; Calculate the number of scans we'll do in this bank.
|
|
|
|
mov edx,[eax].dsurf_rcl2WindowClipS.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the initial bank
|
|
sub eax,eax
|
|
mov al,ch ;total # of scans to copy
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub ch,al ;count this bank's scans off total
|
|
mov byte ptr cjTotalScans,ch ;remember # of scans after this bank
|
|
mov ch,al ;# of scans to do in this bank
|
|
|
|
; Compute the delta to the start of the next scanline of the AND mask
|
|
; and the work area, and the next scan of the screen
|
|
|
|
sub eax,eax
|
|
mov al,cl
|
|
mov edx,WORK_WIDTH
|
|
sub edx,eax
|
|
|
|
; Look up the loop entry point, and start ANDing.
|
|
|
|
mov eax,and_from_screen_entry_table[eax*4] ;look up the loop entry
|
|
push ebp ;preserve stack frame pointer
|
|
mov ebp,ulNextSrcScan ;source offset to next scan
|
|
jmp eax ;enter the ANDing loop
|
|
|
|
.ERRNZ WORK_WIDTH-5
|
|
;-----------------------------------------------------------------------;
|
|
; Register usage for the loop will be:
|
|
;
|
|
; EAX = loop entry address
|
|
; EBX = offset off of SI to the screen source
|
|
; CH = height
|
|
; EDX = offset to next scan of AND mask & work area
|
|
; ESI --> AND mask
|
|
; EDI --> Destination in work area
|
|
;-----------------------------------------------------------------------;
|
|
|
|
and_from_screen_width_5::
|
|
cmp al, [ebx][esi] ;Load latches from work area
|
|
movsb ;AND from screen into work area
|
|
and_from_screen_width_4::
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
and_from_screen_width_3::
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
and_from_screen_width_2::
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
and_from_screen_width_1::
|
|
cmp al, [ebx][esi]
|
|
movsb
|
|
and_from_screen_width_0::
|
|
|
|
add esi,edx ;--> next AND mask
|
|
add edi,edx ;--> next destination
|
|
add ebx,ebp ;--> next source
|
|
|
|
dec ch ;count down scans in this bank
|
|
jz short @F ;bank is finished
|
|
jmp eax ;do next scan in this bank
|
|
|
|
@@:
|
|
pop ebp ;restore stack frame pointer
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
|
|
jz short afscr_done ;no, we're done
|
|
;advance to next dest bank and continue
|
|
; ANDing
|
|
push eax ;preserve entry vector
|
|
push edx ;preserve dest next scan
|
|
mov eax,pdsurf
|
|
sub ebx,[eax].dsurf_pvBitmapStart2WindowS
|
|
;calculate the source offset within the
|
|
; bitmap, because the start address is
|
|
; about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [eax].dsurf_pfnBankControl2Window>, \
|
|
<eax,edx,JustifyTop,MapSourceBank> ;map in the next source bank
|
|
|
|
mov eax,pdsurf
|
|
add ebx,[eax].dsurf_pvBitmapStart2WindowS
|
|
;add back in the bitmap start address
|
|
; to yield the virtual source address
|
|
mov edx,[eax].dsurf_rcl2WindowClipS.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
mov ch,al ;# of scans to do in this bank
|
|
|
|
pop edx ;restore dest next scan
|
|
pop eax ;restore entry vector
|
|
|
|
push ebp ;preserve stack frame pointer
|
|
mov ebp,ulNextSrcScan ;source offset to next scan
|
|
jmp eax ;do the next block of scans
|
|
|
|
afscr_done:
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; and_from_save
|
|
;
|
|
; The given area of the save buffer is ANDed into the work buffer
|
|
;
|
|
; Entry:
|
|
; ESI --> RECT_DATA structure to use
|
|
; EGA programmed for AND mode
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; EBP
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; This is the key to wrapping in the buffer. It is a power of two, and
|
|
; in this case the entire size is 256 bytes. If it wasn't 256 bytes, an
|
|
; and mask could be used for wrapping.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
.ERRNZ SAVE_BUFFER_HEIGHT-32
|
|
.ERRNZ SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
|
|
|
|
and_from_save:
|
|
|
|
.ERRNZ pd_rd
|
|
|
|
; See if we'll wrap in X. If so, split the operation into two parts
|
|
|
|
movzx eax, WORD PTR [esi].rd_ptbWork
|
|
movzx ecx, WORD PTR [esi].rd_ptbSave
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
movzx edx, WORD PTR [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
mov bl, cl
|
|
add bl, dl
|
|
sub bl, SAVE_BUFFER_WIDTH ;BL = is overhang
|
|
jle short and_from_save_do_last_pass ;No overhang
|
|
|
|
sub dl, bl ;Set X extent for pass 1
|
|
mov bh, dl ;Need it for pass 2
|
|
push esi ;Must keep rectangle pointer around
|
|
push ebx
|
|
call and_from_save_do_a_pass ;Process first half
|
|
pop ebx
|
|
pop esi
|
|
movzx eax, WORD PTR [esi].rd_ptbWork
|
|
movzx ecx, WORD PTR [esi].rd_ptbSave
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
movzx edx, WORD PTR [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
add al, bh ;Move right in work area
|
|
mov dl, bl ;Set new extent
|
|
xor cl, cl ;X origin in save area is 0
|
|
|
|
and_from_save_do_last_pass:
|
|
|
|
call and_from_save_do_a_pass
|
|
|
|
PLAIN_RET
|
|
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; and_from_save
|
|
;
|
|
; Inner loop subroutine for and_from_save.
|
|
;
|
|
; Entry:
|
|
; AL = X dest start offset in work area (in bytes)
|
|
; AH = Y dest start offset in work area (in scans)
|
|
; CL = X source start offset in save area (in bytes)
|
|
; CH = Y source start offset in save area (in scans)
|
|
; Upper word of ECX *must* be 0!
|
|
; DL = width to AND (in bytes)
|
|
; DH = height to AND (in scans)
|
|
; EGA programmed for AND mode
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; EBP
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;------------------------------------------------------------------------;
|
|
|
|
and_from_save_do_a_pass:
|
|
|
|
push ebp ;save stack frame pointer
|
|
|
|
push eax
|
|
push ecx
|
|
push edx
|
|
|
|
; Map the cursor bank in as both the read window and the write window, because
|
|
; both the save and work areas are in the cursor bank. Note that we always know
|
|
; that the operation fits in a single bank, which simplifies things
|
|
; considerably.
|
|
|
|
mov esi,pdsurf
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[esi].dsurf_rcl1WindowClip.yTop ;is cursor scan less than
|
|
; current bank?
|
|
jl short afsav_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[esi].dsurf_rcl1WindowClip.yBottom ;cursor scan greater
|
|
; than current bank?
|
|
jl short afsav_ptr_bank_mapped ;no, proper bank already mapped
|
|
afsav_map_ptr_bank:
|
|
|
|
; Map cursor work bank into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [esi].dsurf_pfnBankControl>,<esi,edx,JustifyBottom>
|
|
|
|
afsav_ptr_bank_mapped:
|
|
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
|
|
; Compute the offset within the work area, which is also the offset from
|
|
; the start of the AND mask.
|
|
|
|
xor ebx,ebx
|
|
xchg bl,ah
|
|
add eax,ebx ;*1 + X
|
|
add ebx,ebx ;*2
|
|
add ebx,ebx ;*4
|
|
add ebx,eax ;*5 + X
|
|
mov edi,pPtrWork
|
|
add edi,ebx ;--> destination in work area relative
|
|
; to start of bitmap
|
|
mov esi,[esi].dsurf_pvBitmapStart ;bitmap start virtual address
|
|
push esi ;remember bitmap start for calculating
|
|
; save area pointer
|
|
add edi,esi ;virtual addresss of work area
|
|
; destination start
|
|
mov esi,pAndXor
|
|
add esi,ebx ;--> AND mask
|
|
; Compute the offset within the save
|
|
; area. Note that this is relative to
|
|
; screen_buf
|
|
xor ebx,ebx
|
|
xchg bl,ch ;EBX = ptbSave.ptb_y,
|
|
; ECX = ptbSave.ptb_x
|
|
lea ebx,[ebx*8+ecx] ;EBX = offset in save area
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
|
|
; Compute the adjustment to each scanline.
|
|
|
|
mov cl,dl ;width in bytes to AND
|
|
mov eax,WORK_WIDTH
|
|
sub eax,ecx ;width in bytes to skip from end of one
|
|
; mask/work buffer scan to start of
|
|
; next
|
|
|
|
; Look up the address at which to enter the AND loop.
|
|
|
|
mov ecx,and_from_save_entry_table[ecx*4]
|
|
|
|
; Now get things into the correct registers and enter the loop
|
|
|
|
pop ebp ;get back bitmap start virtual address
|
|
add ebp,pPtrSave ;point to the save area
|
|
push ebp ;remember save area virtual address
|
|
add ebp,ebx ;set correct save buffer address
|
|
sub ebp,esi ;want to use [SI][BP]
|
|
jmp ecx ;enter following code
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Register usage for the loop will be:
|
|
;
|
|
; EAX = delta to next scan of AND mask and work area
|
|
; EBX = offset in save area of scan start
|
|
; ECX = loop address
|
|
; DH = height in scans
|
|
; ESI --> AND mask
|
|
; EDI --> Destination in work area
|
|
; EBP = delta from SI to next byte of save buffer
|
|
;-----------------------------------------------------------------------;
|
|
|
|
and_from_save_width_5::
|
|
cmp al, [ebp][esi] ;Load latches from screen
|
|
movsb ;AND to the work area
|
|
and_from_save_width_4::
|
|
cmp al, [ebp][esi]
|
|
movsb
|
|
and_from_save_width_3::
|
|
cmp al, [ebp][esi]
|
|
movsb
|
|
and_from_save_width_2::
|
|
cmp al, [ebp][esi]
|
|
movsb
|
|
and_from_save_width_1::
|
|
cmp al, [ebp][esi]
|
|
movsb
|
|
and_from_save_width_0::
|
|
|
|
dec dh
|
|
jz short and_from_save_done
|
|
add esi,eax ;--> next AND mask
|
|
add edi,eax ;--> next work buffer scan
|
|
add bl,SAVE_BUFFER_WIDTH ;--> compute address of next
|
|
; scan in the work area
|
|
pop ebp ;restore save area pointer
|
|
push ebp ;push it again, for next time
|
|
add ebp,ebx
|
|
sub ebp,esi ;Want to use SI for incrementing
|
|
|
|
jmp ecx
|
|
|
|
and_from_save_done:
|
|
pop ebp ;clear pushed save area pointer
|
|
|
|
pop ebp ;restore stack frame pointer
|
|
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; copy_things_around
|
|
;
|
|
; Rectangles to be copied from the save area to the screen are
|
|
; processed, followed by the rectangles to be copied from the
|
|
; screen to the save area.
|
|
;
|
|
; Entry:
|
|
; AL = fbFlush
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; BP
|
|
; Registers Destroyed:
|
|
; AX,BX,CX,DX,SI,DI,BP,FLAGS
|
|
; Calls:
|
|
; copy_save_to_screen
|
|
; copy_screen_to_save
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
copy_things_around:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Program the EGA for COPY mode. This will be done using M_PROC_WRITE,
|
|
; M_DATA_READ, DR_???, and setting GRAF_BIT_MASK to 00. All but setting
|
|
; GRAF_BIT_MASK was done by save_hw_regs. All planes were also enabled
|
|
; for writing by save_hw_regs.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov ecx, eax
|
|
mov dx, EGA_BASE + GRAF_ADDR
|
|
mov ax, GRAF_BIT_MASK
|
|
out dx, ax ;Disable all bits
|
|
mov eax, ecx
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Process any copying from the save area to the screen. If FB_OLD_PTR
|
|
; is set, then there cannot be a FB_FLUSH_X or FB_FLUSH_Y.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov esi, ppdOld
|
|
test al, FB_OLD_PTR
|
|
jnz short cta_copy_from_save ;The old rectangle goes
|
|
test al, FB_FLUSH_X
|
|
jz short @F
|
|
mov esi, offset FLAT:rdFlushX
|
|
call copy_save_to_screen
|
|
mov al, fbFlush
|
|
@@:
|
|
test al, FB_FLUSH_Y
|
|
jz short @F
|
|
mov esi, offset FLAT:rdFlushY
|
|
cta_copy_from_save:
|
|
call copy_save_to_screen
|
|
@@:
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Process any copying from the screen to the save area. If FB_NEW_PTR
|
|
; or FB_WORK_RECT is set, then there can't be a FB_FLUSH_X or FB_FLUSH_Y
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mov al, fbAndRead
|
|
mov esi, ppdNew
|
|
test al, FB_NEW_PTR
|
|
jnz short cta_copy_to_save
|
|
mov esi, offset FLAT:rdWork
|
|
test al, FB_WORK_RECT
|
|
jnz short cta_copy_to_save
|
|
|
|
; Some combination of FB_READ_X, FB_READ_Y
|
|
|
|
test al, FB_READ_X
|
|
jz short @F
|
|
mov esi, offset FLAT:rdReadX
|
|
call copy_screen_to_save
|
|
mov al, fbAndRead
|
|
@@:
|
|
test al, FB_READ_Y
|
|
jz short @F
|
|
mov esi, offset FLAT:rdReadY
|
|
cta_copy_to_save:
|
|
call copy_screen_to_save
|
|
@@:
|
|
PLAIN_RET
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; copy_save_to_screen
|
|
;
|
|
; The given rectangle is copied from the save area to the screen
|
|
;
|
|
; Entry:
|
|
; ESI --> RECT_DATA structure to use
|
|
; EGA programmed for COPY mode
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; EBP
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; This is the key to wrapping in the buffer. It is a power of two, and
|
|
; in this case the entire size is 256 bytes. If it wasn't 256 bytes, an
|
|
; and mask could be used for wrapping.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
.ERRNZ SAVE_BUFFER_HEIGHT-32
|
|
.ERRNZ SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
|
|
|
|
copy_save_to_screen:
|
|
|
|
.ERRNZ pd_rd
|
|
|
|
; Map the proper bank into the destination window for the top destination
|
|
; scan line.
|
|
|
|
mov ebx,pdsurf
|
|
mov edx,[esi].rd_ptlScreen.ptl_y
|
|
mov ulCurrentTopScan,edx ;remember where the top dest scan is
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is copy top less than
|
|
; current dest bank?
|
|
jl short sts_map_init_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;copy top greater than
|
|
; current dest bank?
|
|
jl short sts_init_bank_mapped ;no, proper bank already mapped
|
|
sts_map_init_bank:
|
|
|
|
; Map bank containing the top destination (screen) scan line into dest window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyTop,MapDestBank>
|
|
|
|
sts_init_bank_mapped:
|
|
|
|
|
|
; Map the cursor bank into the source window.
|
|
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
|
|
; current source bank?
|
|
jl short sts_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
|
|
; than current source
|
|
; bank?
|
|
jl short sts_ptr_bank_mapped ;no, proper bank already mapped
|
|
sts_map_ptr_bank:
|
|
|
|
; Map cursor work bank into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyBottom,MapSourceBank>
|
|
|
|
sts_ptr_bank_mapped:
|
|
|
|
|
|
; Compute the virtual address of the save area.
|
|
|
|
mov eax,pPtrSave
|
|
add eax,[ebx].dsurf_pvBitmapStart2WindowS ;save area virtual addr
|
|
mov pSaveAddr,eax
|
|
|
|
; Compute the screen address and delta to next scan of the screen.
|
|
|
|
mov edi,lNextScan
|
|
imul edi,[esi].rd_ptlScreen.ptl_y
|
|
add edi,[esi].rd_ptlScreen.ptl_x ;start dest offset in bitmap
|
|
add edi,[ebx].dsurf_pvBitmapStart2WindowD ;start dest virtual addr
|
|
movzx edx,WORD PTR [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
; Calculate the number of scans we'll do in this bank.
|
|
|
|
mov ecx,[ebx].dsurf_rcl2WindowClipD.yBottom
|
|
sub ecx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the initial bank
|
|
sub eax,eax
|
|
mov al,dh ;total # of scans to copy
|
|
cmp eax,ecx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,ecx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub dh,al ;count this bank's scans off total
|
|
mov byte ptr cjTotalScans,dh ;remember # of scans after this bank
|
|
mov dh,al ;# of scans to do in this bank
|
|
|
|
; Calculate the offset from the end of one dest scan line to the next.
|
|
|
|
mov al,dl ;width to copy in bytes
|
|
neg eax
|
|
add eax,lNextScan ;offset from end of one dest scan to start of
|
|
; next
|
|
|
|
; Compute the save area offset.
|
|
|
|
movzx ecx,WORD PTR [esi].rd_ptbSave
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
xor ebx,ebx
|
|
xchg bl,ch
|
|
lea ebx,[ebx*8+ecx]
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
|
|
; Determine if any wrap will occur, and handle it if so.
|
|
|
|
add cl,dl ;add extent (DL) to start X (CL)
|
|
sub cl,SAVE_BUFFER_WIDTH
|
|
jg short save_to_screen_wraps ;CL = amount of wrap
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The copy will not wrap, so we can get into some tighter code for it.
|
|
;
|
|
; Currently:
|
|
; EAX = delta to next destination scan
|
|
; EBX = offset into the save buffer
|
|
; DL = width of copy
|
|
; DH = height of copy
|
|
; EDI --> destination
|
|
;-----------------------------------------------------------------------;
|
|
|
|
copy_save_next_scan:
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
push ebp ;preserve stack frame pointer
|
|
mov ebp,pSaveAddr
|
|
copy_save_next_scan_loop:
|
|
lea esi,[ebp+ebx]
|
|
mov cl,dl
|
|
rep movsb
|
|
add bl,SAVE_BUFFER_WIDTH
|
|
add edi,eax
|
|
dec dh
|
|
jnz short copy_save_next_scan_loop
|
|
|
|
pop ebp ;restore stack frame pointer
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
|
|
jz short sts_done ;no, we're done
|
|
;advance to next dest bank and continue
|
|
; copying
|
|
push eax ;preserve dest next scan
|
|
push edx ;preserve width of copy
|
|
mov esi,pdsurf
|
|
sub edi,[esi].dsurf_pvBitmapStart2WindowD
|
|
;calculate the destination offset
|
|
; within the bitmap, because the start
|
|
; address is about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [esi].dsurf_pfnBankControl2Window>, \
|
|
<esi,edx,JustifyTop,MapDestBank> ;map in the next dest bank
|
|
|
|
add edi,[esi].dsurf_pvBitmapStart2WindowD
|
|
;add back in the bitmap start address
|
|
; to yield the virtual dest address
|
|
mov edx,[esi].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
pop edx ;restore copy width in DL
|
|
mov dh,al ;# of scans to do in this bank
|
|
pop eax ;restore dest next scan
|
|
jmp short copy_save_next_scan ;do the next block of scans
|
|
|
|
sts_done:
|
|
PLAIN_RET
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The copy will wrap, so we have to handle it as two copies
|
|
;
|
|
; Currently:
|
|
; EDI --> destination
|
|
; EAX = delta to next destination scan
|
|
; DL = width of copy
|
|
; DH = height of copy
|
|
; EBX = offset into the save buffer
|
|
; CL = amount of overflow
|
|
;-----------------------------------------------------------------------;
|
|
|
|
save_to_screen_wraps:
|
|
sub dl,cl ;set extent of first copy
|
|
mov byte ptr jPostWrapWidth,cl ;set extent of second copy
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
|
|
copy_save_next_scan_wrap_loop:
|
|
mov esi,pSaveAddr
|
|
add esi,ebx
|
|
mov cl,dl
|
|
rep movsb
|
|
sub esi,SAVE_BUFFER_WIDTH
|
|
mov cl,byte ptr jPostWrapWidth
|
|
rep movsb
|
|
add bl,SAVE_BUFFER_WIDTH
|
|
add edi,eax
|
|
dec dh
|
|
jnz short copy_save_next_scan_wrap_loop
|
|
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
|
|
jz short sts_done ;no, we're done
|
|
;advance to next dest bank and continue
|
|
; copying
|
|
push eax ;preserve dest next scan
|
|
push edx ;preserve width of copy
|
|
mov esi,pdsurf
|
|
sub edi,[esi].dsurf_pvBitmapStart2WindowD
|
|
;calculate the destination offset
|
|
; within the bitmap, because the start
|
|
; address is about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [esi].dsurf_pfnBankControl2Window>, \
|
|
<esi,edx,JustifyTop,MapDestBank> ;map in the next dest bank
|
|
|
|
add edi,[esi].dsurf_pvBitmapStart2WindowD
|
|
;add back in the bitmap start address
|
|
; to yield the virtual dest address
|
|
mov edx,[esi].dsurf_rcl2WindowClipD.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
pop edx ;restore copy width in DL
|
|
mov dh,al ;# of scans to do in this bank
|
|
pop eax ;restore dest next scan
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
jmp copy_save_next_scan_wrap_loop ;do the next block of scans
|
|
|
|
page
|
|
|
|
;--------------------------Private-Routine------------------------------;
|
|
; copy_screen_to_save
|
|
;
|
|
; The given rectangle is copied from the screen to the save area
|
|
;
|
|
; Entry:
|
|
; ESI --> RECT_DATA structure to use
|
|
; EGA programmed for COPY mode
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; No error return.
|
|
; Registers Preserved:
|
|
; EBP
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
|
|
; Calls:
|
|
; None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; This is the key to wrapping in the buffer. It is a power of two, and
|
|
; in this case the entire size is 256 bytes. If it wasn't 256 bytes, an
|
|
; and mask could be used for wrapping.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
.ERRNZ SAVE_BUFFER_HEIGHT-32
|
|
.ERRNZ SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
|
|
|
|
copy_screen_to_save:
|
|
|
|
.ERRNZ pd_rd
|
|
|
|
; Map the proper bank into the source window for the top source scan line.
|
|
|
|
mov ebx,pdsurf
|
|
mov edx,[esi].rd_ptlScreen.ptl_y
|
|
mov ulCurrentTopScan,edx ;remember where the top source scan is
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is copy top less than
|
|
; current source bank?
|
|
jl short scrts_map_init_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;copy top greater than
|
|
; current source bank?
|
|
jl short scrts_init_bank_mapped ;no, proper bank already mapped
|
|
scrts_map_init_bank:
|
|
|
|
; Map bank containing the top source (screen) scan line into source window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyTop,MapSourceBank>
|
|
|
|
scrts_init_bank_mapped:
|
|
|
|
|
|
; Map the cursor bank into the dest window.
|
|
|
|
mov edx,ulPtrBankScan ;scan line at end of cursor work bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is cursor scan less than
|
|
; current dest bank?
|
|
jl short scrts_map_ptr_bank ;yes, map in proper bank
|
|
cmp edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;cursor scan greater
|
|
; than current dest
|
|
; bank?
|
|
jl short scrts_ptr_bank_mapped ;no, proper bank already mapped
|
|
scrts_map_ptr_bank:
|
|
|
|
; Map cursor work bank into dest window.
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
|
|
<ebx,edx,JustifyBottom,MapDestBank>
|
|
|
|
scrts_ptr_bank_mapped:
|
|
|
|
|
|
; Compute the virtual address of the save area.
|
|
|
|
mov eax,pPtrSave
|
|
add eax,[ebx].dsurf_pvBitmapStart2WindowD ;save area virtual addr
|
|
mov pSaveAddr,eax
|
|
|
|
; Compute the source screen address and delta to next scan of the screen.
|
|
|
|
mov edi,lNextScan
|
|
imul edi,[esi].rd_ptlScreen.ptl_y
|
|
add edi,[esi].rd_ptlScreen.ptl_x ;start source offset in bitmap
|
|
add edi,[ebx].dsurf_pvBitmapStart2WindowS ;start source virtual
|
|
; address
|
|
movzx edx,WORD PTR [esi].rd_sizb
|
|
|
|
.ERRNZ sizb_cy-sizb_cx-1
|
|
|
|
; Calculate the number of scans we'll do in this bank.
|
|
|
|
mov ecx,[ebx].dsurf_rcl2WindowClipS.yBottom
|
|
sub ecx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the initial bank
|
|
sub eax,eax
|
|
mov al,dh ;total # of scans to copy
|
|
cmp eax,ecx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,ecx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub dh,al ;count this bank's scans off total
|
|
mov byte ptr cjTotalScans,dh ;remember # of scans after this bank
|
|
mov dh,al ;# of scans to do in this bank
|
|
|
|
; Calculate the offset from the end of one source scan line to the next.
|
|
|
|
mov al,dl ;width to copy in bytes
|
|
neg eax
|
|
add eax,lNextScan ;offset from end of one source scan to start of
|
|
; next
|
|
|
|
; Compute the save area offset.
|
|
|
|
movzx ecx,WORD PTR [esi].rd_ptbSave
|
|
|
|
.ERRNZ ptb_y-ptb_x-1
|
|
|
|
xor ebx,ebx
|
|
xchg bl,ch
|
|
lea ebx,[ebx*8+ecx]
|
|
|
|
.ERRNZ SAVE_BUFFER_WIDTH-8
|
|
|
|
mov esi,edi ;ESI -> initial source byte
|
|
|
|
; Determine if any wrap will occur, and handle it if so.
|
|
|
|
add cl,dl ;add extent (DL) to start X (CL)
|
|
sub cl,SAVE_BUFFER_WIDTH
|
|
jg short screen_to_save_wraps ;CL = amount of wrap
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The copy will not wrap, so we can get into some tighter code for it.
|
|
;
|
|
; Currently:
|
|
; EAX = delta to next source scan
|
|
; EBX = offset into the save buffer
|
|
; DL = width of copy
|
|
; DH = height of copy
|
|
; ESI --> source
|
|
;-----------------------------------------------------------------------;
|
|
|
|
copy_screen_next_scan:
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
push ebp ;preserve stack frame pointer
|
|
mov ebp,pSaveAddr
|
|
copy_screen_next_scan_loop:
|
|
lea edi,[ebp+ebx]
|
|
mov cl,dl
|
|
rep movsb
|
|
add bl,SAVE_BUFFER_WIDTH
|
|
add esi,eax
|
|
dec dh
|
|
jnz short copy_screen_next_scan_loop
|
|
|
|
pop ebp ;restore stack frame pointer
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next source bank)?
|
|
jz short scrts_done ;no, we're done
|
|
;advance to next source bank and
|
|
; continue copying
|
|
push eax ;preserve source next scan
|
|
push edx ;preserve width of copy
|
|
mov edi,pdsurf
|
|
sub esi,[edi].dsurf_pvBitmapStart2WindowS
|
|
;calculate the source offset
|
|
; within the bitmap, because the start
|
|
; address is about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyTop,MapSourceBank> ;map in the next source bank
|
|
|
|
add esi,[edi].dsurf_pvBitmapStart2WindowS
|
|
;add back in the bitmap start address
|
|
; to yield the virtual source address
|
|
mov edx,[edi].dsurf_rcl2WindowClipS.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
pop edx ;restore copy width in DL
|
|
mov dh,al ;# of scans to do in this bank
|
|
pop eax ;restore source next scan
|
|
jmp short copy_screen_next_scan ;do the next block of scans
|
|
|
|
scrts_done:
|
|
PLAIN_RET
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; The copy will wrap, so we have to handle it as two copies
|
|
;
|
|
; Currently:
|
|
; EAX = delta to next source scan
|
|
; EBX = offset into the save buffer
|
|
; CL = amount of overflow
|
|
; DL = width of copy
|
|
; DH = height of copy
|
|
; ESI --> source
|
|
;-----------------------------------------------------------------------;
|
|
|
|
screen_to_save_wraps:
|
|
sub dl,cl ;set extent of first copy
|
|
mov byte ptr jPostWrapWidth,cl ;set extent of second copy
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
|
|
copy_screen_next_scan_wrap_loop:
|
|
mov edi,pSaveAddr
|
|
add edi,ebx
|
|
mov cl,dl
|
|
rep movsb
|
|
sub edi,SAVE_BUFFER_WIDTH
|
|
mov cl,byte ptr jPostWrapWidth
|
|
rep movsb
|
|
add bl,SAVE_BUFFER_WIDTH
|
|
add esi,eax
|
|
dec dh
|
|
jnz short copy_screen_next_scan_wrap_loop
|
|
|
|
cmp byte ptr cjTotalScans,0 ;more lines (in next source bank)?
|
|
jz short scrts_done ;no, we're done
|
|
;advance to next source bank and
|
|
; continue copying
|
|
push eax ;preserve source next scan
|
|
push edx ;preserve width of copy
|
|
mov edi,pdsurf
|
|
sub esi,[edi].dsurf_pvBitmapStart2WindowS
|
|
;calculate the source offset
|
|
; within the bitmap, because the start
|
|
; address is about to move
|
|
mov edx,ulCurrentTopScan
|
|
|
|
; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
|
|
|
|
ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
|
|
<edi,edx,JustifyTop,MapSourceBank> ;map in the next source bank
|
|
|
|
add esi,[edi].dsurf_pvBitmapStart2WindowS
|
|
;add back in the bitmap start address
|
|
; to yield the virtual source address
|
|
mov edx,[edi].dsurf_rcl2WindowClipS.yBottom
|
|
sub edx,ulCurrentTopScan ;max # of scans that can be handled in
|
|
; the new bank
|
|
sub eax,eax
|
|
mov al,byte ptr cjTotalScans ;remaining scan count
|
|
cmp eax,edx ;can we handle all remaining scans in
|
|
; this bank?
|
|
jb short @F ;yes
|
|
mov eax,edx ;no, so we'll do the whole bank's worth
|
|
@@:
|
|
add ulCurrentTopScan,eax ;set top scan for next bank
|
|
sub byte ptr cjTotalScans,al ;count this bank's scans off total
|
|
pop edx ;restore copy width in DL
|
|
mov dh,al ;# of scans to do in this bank
|
|
pop eax ;restore source next scan
|
|
sub ecx,ecx ;prepare for loading CL in loop
|
|
jmp short copy_screen_next_scan_wrap_loop ;do the next block of scans
|
|
|
|
endProc vDrawPointer
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; vDIB4Convert*
|
|
;
|
|
; Converts the specified number of source 4 bpp bits into the
|
|
; buffer. These are support routines for vDIB4Planer, where a
|
|
; source byte converts into two aligned bits
|
|
;
|
|
; Entry:
|
|
; EAX 31:8 = 0
|
|
; EBP --> Bit conversion table
|
|
; ESI --> Source bitmap
|
|
; EDI --> Planer destination
|
|
; ECX = Loop count
|
|
; Exit:
|
|
; EBP --> Bit conversion table
|
|
; ESI --> Next source byte
|
|
; EDI --> Next planer destination
|
|
; EDX = Last planer byte accumulated
|
|
; Registers Destroyed:
|
|
; EAX,ECX,EDX
|
|
; Registers Preserved:
|
|
;-----------------------------------------------------------------------;
|
|
|
|
extrn aulDefBitMapping:dword
|
|
|
|
vDIB4Convert8 proc
|
|
mov al,[esi] ; 1 cycle 486
|
|
inc esi ; 1 cycle 486
|
|
; lodsb
|
|
mov ebx,eax
|
|
shr eax,4
|
|
and ebx,00001111b
|
|
mov edx,[ebp][eax*4]
|
|
shl edx,1
|
|
or edx,[ebp][ebx*4]
|
|
vDIB4Convert6:
|
|
mov al,[esi] ; 1 cycle 486
|
|
inc esi ; 1 cycle 486
|
|
; lodsb
|
|
shl edx,1
|
|
mov ebx,eax
|
|
shr eax,4
|
|
and ebx,00001111b
|
|
or edx,[ebp][eax*4]
|
|
shl edx,1
|
|
or edx,[ebp][ebx*4]
|
|
vDIB4Convert4:
|
|
mov al,[esi] ; 1 cycle 486
|
|
inc esi ; 1 cycle 486
|
|
; lodsb
|
|
shl edx,1
|
|
mov ebx,eax
|
|
shr eax,4
|
|
and ebx,00001111b
|
|
or edx,[ebp][eax*4]
|
|
shl edx,1
|
|
or edx,[ebp][ebx*4]
|
|
vDIB4Convert2:
|
|
mov al,[esi] ; 1 cycle 486
|
|
inc esi ; 1 cycle 486
|
|
; lodsb
|
|
shl edx,1
|
|
mov ebx,eax
|
|
shr eax,4
|
|
and ebx,00001111b
|
|
or edx,[ebp][eax*4]
|
|
shl edx,1
|
|
or edx,[ebp][ebx*4]
|
|
mov [edi][4*0],dl
|
|
mov [edi][4*1],dh
|
|
ror edx,16
|
|
mov [edi][4*2],dl
|
|
mov [edi][4*3],dh
|
|
inc edi
|
|
dec ecx
|
|
jnz vDIB4Convert8
|
|
ret
|
|
|
|
vDIB4Convert8 endp
|
|
|
|
page
|
|
;-----------------------------------------------------------------------;
|
|
; vConvertDIBPointer
|
|
;
|
|
; Converts the passed DIB into a planer format, then synthesizes the
|
|
; XOR mask.
|
|
;
|
|
; Entry:
|
|
; ESI --> Color Bits, 4bpp format
|
|
; EDI --> Planer destination
|
|
; EAX = fIsDFB
|
|
; ECX = Bitmap height
|
|
; EBP = pulXlate for color mapping
|
|
; DX = wFlags
|
|
; Exit:
|
|
; None
|
|
; Registers Destroyed:
|
|
; EAX,EBX,ECX,EDX,ESI,EDI,Flags
|
|
; Registers Preserved:
|
|
;-----------------------------------------------------------------------;
|
|
|
|
vConvertDIBPointer proc
|
|
|
|
; Convert the scans as necessary into planer format. We'll assume a fixed
|
|
; size of 32 bits wide
|
|
|
|
push edx ;Save
|
|
push edi
|
|
|
|
convert_top:
|
|
push ecx ;Save loop count
|
|
push edi ;Save destination pointer
|
|
push esi ;Save source pointer
|
|
mov ecx,PTR_WIDTH
|
|
|
|
and eax,eax ;is cursor a dfb
|
|
jnz short @F ;yes
|
|
;no,DIB
|
|
xor eax,eax ;Needs to be zero initialized
|
|
call vDIB4Convert8 ;Convert one scan
|
|
jmp short done_with_cvt
|
|
@@:
|
|
rep movsd ;DFB
|
|
done_with_cvt:
|
|
|
|
pop esi
|
|
pop edi
|
|
pop ecx
|
|
add edi,16 ;--> next destination scan
|
|
add esi,16 ;--> next source scan
|
|
dec ecx
|
|
jnz convert_top
|
|
|
|
; The bitmap has been converted into planer format. If it needs flipping,
|
|
; then flip it
|
|
|
|
pop esi ;Start of plane 0
|
|
pop edx
|
|
or dl,dl
|
|
js skipping_first_invert ;Color bitmap is TOPDOWN
|
|
mov ecx,PTR_HEIGHT / 2 ;* scans to flip
|
|
lea edi,[esi][PTR_HEIGHT*4*4] ;--> last scan
|
|
|
|
flip_next_scan:
|
|
sub edi,16 ;decrement target pointer
|
|
|
|
mov eax,[esi+00h] ;Load
|
|
mov ebx,[edi+00h]
|
|
mov [edi+00h],eax ;Swap
|
|
mov [esi+00h],ebx ;Save
|
|
|
|
mov eax,[esi+04h] ;Load
|
|
mov ebx,[edi+04h]
|
|
mov [edi+04h],eax ;Swap
|
|
mov [esi+04h],ebx ;Save
|
|
|
|
mov eax,[esi+08h] ;Load
|
|
mov ebx,[edi+08h]
|
|
mov [edi+08h],eax ;Swap
|
|
mov [esi+08h],ebx ;Save
|
|
|
|
mov eax,[esi+0Ch] ;Load
|
|
mov ebx,[edi+0Ch]
|
|
mov [edi+0Ch],eax ;Swap
|
|
mov [esi+0Ch],ebx ;Save
|
|
|
|
add esi,16 ;increment source pointer
|
|
loop flip_next_scan
|
|
|
|
skipping_first_invert:
|
|
ret
|
|
|
|
vConvertDIBPointer endp
|
|
|
|
_TEXT$01 ends
|
|
|
|
end
|