;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = POINTER.ASM
;*
;* DESCRIPTIVE NAME = Pointer shape routines
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/16/88
;*
;* DESCRIPTION  
;*
;*  This file contains the pointer shape routines required to draw the       
;*  pointer shape on the 8514.
;*                                                                           
;*  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 poin    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 semaphore  
;*  at higher level code.                                                    
;*              
;*  These routines must use the DS passed into the routines.  It
;*  is possible that we could be called out-of-context to draw
;*  the pointer.  If DataBASE, CodeData, or whatever is used, it
;*  might not be a valid selector for the current process.
;*
;* FUNCTIONS    move_pointers
;*              create_masks_1_thru_7
;*              pointer_off
;*              draw_pointer
;*              map_xy
;*              compute_rects
;*              clip_rects
;*              do_clipping
;*              xor_to_screen
;*              color_pointer_to_screen
;*              cps_do_a_pass
;*              and_into_work
;*              and_from_screen
;*              and_from_save
;*              copy_things_around
;*              copy_save_to_screen
;*              copy_screen_to_save
;*
;*              Public Data:          x_cell
;*                                    y_cell
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   03/16/88                     Author:  Geoff Shapiro [geoffs]
;*   04/28/88                     Walt Moore [waltm] Complete rewrite.
;*                                Added X,Y as parameters
;*   01/16/89                     Walt Moore [waltm] PTR HM00371.  Didn't
;*                                handle a mask being all FFs or 00s.
;*   02/08/89                     Hock Lee [hockl] Added color pointer
;*                                (DCR 24327).
;*****************************************************************************/

        .286p

        .xlist
        include cmacros.inc
        include pmgre.inc
        include driver.inc
        include pointer.inc
        include 8514.inc
        include 8514mem.inc
        include assert.mac
        include njmp.mac
        .list

        .286p

        ??_out  pointer

        Public  move_pointers
        Public  draw_pointer
        Public  pointer_off


sBegin  PtrData

;/*
;** This is a copy of the screen selector which we can use at interrupt
;** time.  It is initialized in one_time_init in INIT.ASM.
;*/


        public  selScreenPtr
selScreenPtr    dw      -1

;/*
;**       The following values are required here because they are needed
;**       in PtrData at interrupt time. They are initialized with values
;**       from Data variables at enable time (once all prior initialization
;**       has been finished)
;*/

        public  Ptr_sd_cx, Ptr_sd_cy, Ptr_hwFlags
Ptr_sd_cx       dw      1024                      ; assume 1kx768 mode
Ptr_sd_cy       dw      768                       ; ditto
Ptr_hwFlags     dw      ?                         ; will always be initialized

;/*
;**       old_valid contains a flag which is used to indicate
;**       whether or not the contents of the pointer save area
;**       contains valid data.
;*/

old_valid       Db      OLD_IS_INVALID            ; true if old ptr contains valid data
OLD_IS_INVALID  Equ     0                         ; no pointer in save area
OLD_IS_VALID    Equ     1                         ; pointer in save area

;/*
;**       (x_cell,y_cell) is the location of the pointer on the screen.
;**       These locations are only updated whenever a pointer is drawn.
;*/

                Public  x_cell,y_cell            ; pointer exclusion needs these
x_cell          Dw      0
y_cell          Dw      0

;/*
;**       old_x_cell and old_y_cell contain the (X,Y) on the
;**       screen where the contents of the save_area maps to.
;**       These cells are only valid if old_valid = OLD_IS_VALID
;*/

        Public  old_x_cell,old_y_cell
old_x_cell      Dw      0
old_y_cell      Dw      0


;/*
;**       and_x_cell and and_y_cell are the upper left x and y
;**       coordinates of the offscreen area of the 8514/A which contains
;**       the bit descriptions of the pointer AND mask.
;**
;**       NOTE: These are set up at load time dependent on the hardware
;**             configuration if the configuration is a 512 line mode.
;*/

        Public  and_x_cell,and_y_cell
and_x_cell      Dw      0
and_y_cell      Dw      768

;/*
;**       xor_x_cell and xor_y_cell are the upper left x and y
;**       coordinates of the offscreen area of the 8514/A which contains
;**       the bit descriptions of the pointer XOR mask.
;**
;**       NOTE: These are set up at load time dependent on the hardware
;**             configuration if the configuration is a 512 line mode.
;*/

        Public  xor_x_cell,xor_y_cell
xor_x_cell      Dw      ?
xor_y_cell      Dw      768

;/*
;**       save_x_cell and save_y_cell are the upper left x and y
;**       coordinates of the save area for the bits which must be saved
;**       when a pointer is visible on the screen.
;**
;**       NOTE: These are set up at load time dependent on the hardware
;**             configuration if the configuration is a 512 line mode.
;*/

        Public  save_x_cell,save_y_cell
save_x_cell     Dw      ?
save_y_cell     Dw      768

;/*
;**       clrptr_x_cell and clrptr_y_cell are the upper left x and y
;**       coordinates of the bitmap used for the color pointer.
;*/

        Public  clrptr_x_cell,clrptr_y_cell
clrptr_x_cell     dw      ?
clrptr_y_cell     dw      768

        Public  workptr_x_cell,workptr_y_cell
workptr_x_cell    dw      ?
workptr_y_cell    dw      768

        externW cxPointer                         ; current pointer width
        externW cyPointer                         ; current pointer height

;/*
;** fbPointer tells us if the pointer is color
;*/

fbPointer       db      0
FBPTR_COLOR     equ     00000001b

externW PtrPatCacheY

sEnd    PtrData


sBegin  PtrCode
        assumes cs,PtrCode

        externW PtrCodeData

        page
;/***************************************************************************
;*
;* FUNCTION NAME = move_pointers
;*
;* DESCRIPTION   = The pointer is defined by an AND and XOR mask, and in the    
;*                 case of color pointers a color bitmap.  This routine takes   
;*                 pointers to these "bitmaps" as arguments, and copies these   
;*                 "bitmaps" to device off-screen memory where the interrupt    
;*                 level routine that draws the pointer can easily access them. 
;*
;*                 Registers Preserved:
;*                       BP                      
;*                 Registers Destroyed:          
;*                       AX,BX,CX,DX,SI,DI,DS,ES 
;*                 Calls:
;*                       create_masks_1_thru_7
;*
;* INPUT         = BX = width in pels for exclusion hit test
;*                 DX = height in scans for exclusion hit test
;* OUTPUT        = AX = width in pels for exclusion hit test
;*                 DX = height in scans for exclusion hit test
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

;/*
;** compose 8514/A command to output cursor masks
;*/

CMD_WCUR        =       (\
                         CMD_C_HRECT+CMD_BYTE_LO+CMD_BYTE+CMD_FV_VAR+\
                         CMD_DX+CMD_DY+CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW_W\
                        )


        assumes ds,nothing                        ;DS is pointing to bitmap
        assumes es,nothing

cProc   move_pointers,<NEAR,PUBLIC,NO_ATTRPROF>
        parmD   pBitsAndXor                       ;--> AND/XOR bitmap bitmask 
        parmD   pBitsColor                        ;--> color bitmap bitmask
        parmW   wFlags                            ; not used by 8514 driver

        localW  cxPtr                             ;pointer width
        localW  cyPtr                             ;pointer height
cBegin
        mov     cxPtr,bx
        mov     cyPtr,dx

        lds     si,pBitsAndXor                    ;DS:SI --> AND/XOR mask
        assumes ds,nothing

        mov     es,PtrCodeData                    ; our data seg
        assumes es,PtrData

;/*
;** issue a rectangle command with pattern source being the AND and XOR masks
;** to be loaded onto the board
;*/


        WaitQ   7                                 ; need room in the queue
        Mov     Bx,and_x_cell                     ; set up scissor rectangle
        Mov     Ax,Bx
     ifdef VIEW_MASKS
        xor ax,ax
     endif
        Or      Ah,High XMIN_2DECODE
        .errnz  Low XMIN_2DECODE
        outwQ   XMIN,Ax
        mov     ax,cxPtr                          ; width of the cursor
        add     ax,ax                             ; *2 to account for mask,data
        dec     ax                                ; 0-based width
        outwQ   LX,ax                             ; 0-based width of the pointer buffer
        add     ax,ax                             ; width of AND/XOR/SAVE/COLOR bitmaps
        inc     ax                                ; our DEC above just doubled, so INC
        add     ax,bx                             ; right side of mask,data buffer
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX,Ax
        Mov     Cx,and_y_cell
        Mov     Ax,Cx
     ifdef VIEW_MASKS
        xor ax,ax
     endif
        Or      Ah,High YMIN_2DECODE
        .errnz  Low YMIN_2DECODE
        outwQ   YMIN,Ax
        mov     ax,cyPtr                          ; 1-based height of the cursor
        dec     ax                                ; 0-based height
        outwQ   LY,ax                             ; 0-based height of a pointer
        .errnz  LY_2DECODE
        add     ax,cx                             ; bottom of cursor buffer
        or      ah,high YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX,Ax
        outbQ   WRITE_ENABLE,WRITE_PLANE_0 ; write to plane 0 only

        WaitQ   6
        outwQ   X0,Bx                             ; send out mask,data x coordinate
        outwQ   Y0,Cx                             ; send out mask,data y coordinate
        outbQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_ZEROS); write 0s to bg
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_ONES); write 1s to fg
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_WCUR               ; command to output cursor masks


twistbits16     macro
        Lodsw                                     ; 4 nibbles -- N2|N3|N0|N1
        Rol     Ah,4                              ; now     -- N3|N2|N0|N1
        Ror     Ax,4                              ; now     -- N1|N3|N2|N0
        Rol     Ah,4                              ; now     -- N3|N1|N2|N0
        Rol     Ax,1                              ; as above, shifted up 1 bit
        Out     Dx,Ax                             ; output N1|N0
        Ror     Ax,4
        Out     Dx,Ax                             ; output N3|N2
        endm

twistbits8      macro
        Lodsb                                     ; 4 nibbles -- N2|N3|N0|N1
        Rol     Ah,4                              ; now     -- N3|N2|N0|N1
        Ror     Ax,4                              ; now     -- N1|N3|N2|N0
        Rol     Ah,4                              ; now     -- N3|N1|N2|N0
        Rol     Ax,1                              ; as above, shifted up 1 bit
        Out     Dx,Ax                             ; output N1|N0
        endm

;/*
;** The 8514/A is now patiently waiting for us to download patterns of the
;** AND and XOR masks. We do this in the format expected by the adapter.
;*/

        mov     cx,cyPtr                          ; for # of scanlines in a pointer
        mov     dx,COLOR_1                        ; variable data port
        cld                                       ; work up in address

        cmp     cx,40                             ; the 40 wide cursor ?
        nje     mp_loop40

        mov     bl,byte ptr cxPtr                ; width in pixels of pointer
        shr     bl,3                              ; width in bytes of pointer
        mov     al,cl                             ; height in scans of pointer
        mul     bl                                ; ax = # bytes in pointer
        mov     di,ax                             ; di = # bytes in pointer
        sub     ax,bx
        mov     bx,ax                             ; bx = # bytes in pointer - 1 scan

ifdef   FIREWALLS
        cmp     cx,64
        je      mp_loop32
        cmp     cx,32
        je      mp_loop32
        assert  E                                 ; force assertion failure
endif   ;FIREWALLS

public  mp_loop32                                 ; handles 32 or 64 wide bitmaps
mp_loop32:

;/*
;** output a scanline of the AND mask
;*/

        twistbits16
        twistbits16
        cmp     di,128                            ; the 32 wide cursor ?
        je      @F                                ; yes...
        twistbits16
        twistbits16
@@:

;/*
;** output a scanline of the XOR mask
;*/

        add     si,bx                             ; -> to corresponding XOR mask scanline
        twistbits16
        twistbits16
        cmp     di,128                            ; the 32 wide cursor ?
        je      @F                                ; yes...
        twistbits16
        twistbits16
@@:
        sub     si,di                             ; -> to next scanline of AND mask
        nloop   mp_loop32                         ; any more scanlines ?
        jmp     bits_twisted


public  mp_loop40
mp_loop40:

;/*
;** output a scanline of the AND mask
;*/

        twistbits16                               ; (+2)
        twistbits16                               ; (+2)
        twistbits8                                ; (+1)

;/*
;** output a scanline of the XOR mask
;*/

        add     si,320-5                          ; -> to corresponding XOR mask scanline
                                                  ; +320 (64/8*40) to get to XOR mask
                                                  ; -5 because lodsbs in twistbits
        twistbits16
        twistbits16
        twistbits8
        sub     si,320-3                          ; -> to next scanline of AND mask
                                                  ; 64/8*40  (40 wide scan take 64 bits)
                                                  ; -3 for dword aligned bits in mask
        loop    mp_loop40                         ; any more scanlines ?
        assert  cxPtr,E,40                        ; assumes 40x40!
        assert  cyPtr,E,40                        ; assumes 40x40!

bits_twisted:

        mov     ds,PtrCodeData                    ; required for return
        assumes ds,PtrData

;/*
;** Note that we copied the whole bitmap (XOR and AND masks) at once.
;** But internally we view these as separate entities.  The size of these
;** is not fixed, but we want to pack them.  So we must now adjust our
;** pointers to these masks and the following buffers for saving what is
;** behind the pointer and the color bitmap cell.
;*/

        mov     ax,and_x_cell                     ; position of 
        mov     bx,cxPtr                          ; width of pointer
        add     ax,bx                             ; position of xor mask
        mov     xor_x_cell,ax                     ; save it
        add     ax,bx                             ; position of save area
        mov     save_x_cell,ax                    ; save it
        add     ax,bx                             ; position of save area
        mov     clrptr_x_cell,ax                 ; save it
        add     ax,bx                             ; position of work area
        mov     workptr_x_cell,ax                ; save it

;/*
;** That takes care of the AND and XOR masks.  Do we also have a color
;** bitmap?  If so then we need to copy it up to it's off-screen save
;** area and then "process it" (see below).
;*/

public wes1
wes1:
        mov     fbPointer,0                       ;Assume it's a b/w pointer
        mov     cx,pBitsColor.sel
ifdef   WITH_AND_MASK
        njcxz   bw_ptr
else
        jcxz    bw_ptr
endif;  WITH_AND_MASK
        mov     fbPointer,FBPTR_COLOR            ;Indicate color pointer
        mov     ds,cx
        assumes ds,nothing
        mov     si,pBitsColor.off                ; DS:SI --> color bitmap

;/*
;** copy the bitmap to offscreen memory
;*/

CMDPATCOLOR     =       (\
                         CMD_C_HRECT+CMD_BYTE_LO+CMD_BYTE+CMD_FV_VAR+CMD_DY+\
                         CMD_DX+CMD_MA_ACCESS+CMD_PA_ONE+CMD_RW_W\
                        )

        WaitQ   8
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES)    ; pattern always 1s
        outbQ   FUNCTION_1,(FUNC_2OP_VAR+FUNC_S) ; so only FUNC_1 applies
        outbQ   WRITE_ENABLE,WRITE_ALL_PLANES

        mov     ax,cxPtr
        dec     ax                                ; LX is 0-based
        outwQ   LX,ax
        mov     bx,cyPtr                          ; height of pointer
        mov     ax,bx
        dec     ax                                ; LY is 0-based
        outwQ   LY,ax
        .errnz  LY_2DECODE
        outwQ   X0,clrptr_x_cell                 ; starting x of color pointer cache
        outwQ   Y0,clrptr_y_cell                 ; starting y of color pointer cache
        outwQ   CMD_FLAGS,CMDPATCOLOR   ; do entire cached pattern
        mov     dx,COLOR_1                        ; variable data port

        assert  ND                                ; assert that a CLD was done above
color_mp_loop:
        mov     cx,cxPtr                          ; one byte / pel
        shr     cx,1                              ; two pels / word
        assert  NC
        rep     outsw                             ; send out one scan of bitmap
        dec     bx
        jnz     color_mp_loop

;/*
;** compose 8514/A command used to write the masks to the screen
;*/

CMD_WMASK       =       (CMD_C_CRECT+CMD_DX+CMD_DY+CMD_PA_FOUR)

ifdef   WITH_AND_MASK

;/*
;** pre-processing the color bitmap:
;** draw_pointer will simply want to OR the bitmap onto the screen.
;** That requires us to ZERO out the bitmap at the locations where the
;** screen is to be left alone or inverted.  This is where the AND MASK
;** is "1".  So to process the bitmap we AND the bitmap with
;** NOT the AND MASK.
;*/

public wes2             ; poke holes in the color bitmap
wes2:

;/*
;** Poke holes in the color bitmap.
;*/

        WaitQ   2                                 ; need room in the queue
        outbQ   READ_ENABLE,READ_PLANE_0 ; read from just the 0th plane
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)
        WaitQ   7                                 ; need room in the queue
        outwQ   X0,and_x_cell                     ; starting x of color pointer cache
        outwQ   Y0,and_y_cell                     ; starting y of color pointer cache
        outwQ   X1,clrptr_x_cell                 ; send out destination x coordinate
        outwQ   Y1,clrptr_y_cell                 ; send out destination y coordinate
        outbQ   FUNCTION_0,(FUNC_2OP_COPY+FUNC_D)    ; leavealone where AND MASK is 0.
        outbQ   FUNCTION_1,(FUNC_2OP_COPY+FUNC_ZEROS); is zero.  0 otherwise.
        outwQ   CMD_FLAGS,CMD_WMASK              ; command to write it
endif;  WITH_AND_MASK

bw_ptr:
        mov     ax,cxPtr
        mov     dx,cyPtr
cEnd
page


;/***************************************************************************
;*
;* FUNCTION NAME = draw_pointer   
;*
;* DESCRIPTION   = 
;*
;*       Draw a pointer based at ptsX and ptsY
;*     
;*       The currently defined pointer is drawn.  If the old pointer is
;*       currently on the screen, it is removed.
;*     
;*       The idea here is that 32x32 and 40x40 pointers will be fully
;*       manipulated off screen and then blitted to the screen.
;*     
;*       1) copy the "union rectangle" of the old pointer position and the new
;*          pointer position to the work area
;*       2) copy the save buffer to the work area to cover the old pointer
;*          shape so the work area is complete
;*       3) copy from the work area the image of the area that will be obscured
;*          by the new pointer postion
;*       4) apply mask1 to work area (may be AND or XOR mask)
;*       5) apply mask1 to work area (may be AND or XOR mask)
;*       6) if color copy the color bitmap to work area
;*       7) copy the appropriate area of the work buffer (it now contains the
;*          the new pointer image) to the new pointer position.
;*                                                                            
;*                 Registers Preserved:                
;*                       BP,DS                         
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,ES,FLAGS    
;*                 Calls:
;*                       pointer_off
;*
;*                 Restrictions:
;*                       fGrimReaper must have been check prior to calling this routine.
;*
;* INPUT         = DS = PtrData
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

;/*
;** compose 8514/A command used to save obscured portion of framebuffer
;*/
                \
CMD_WSAVE       =       (\
                         CMD_C_CRECT+CMD_FV_FIX+CMD_DX+\
                         CMD_DY+CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW_W\
                        )

;/*
;** Copy the contents of the save buffer back to the location in the framebuffer
;** from which it was taken
;**
;** Issue a copy rectangle command. The source will be the bits currently
;** in the save buffer. The destination will be the spot in the framebuffer
;** from which the bits originally were taken.
;*/

setclip macro    xMin,yMin,xMax,yMax
        WaitQ   6                                 ; need room in the queue
        mov     ax,xMin
        or      ah,High XMIN_2DECODE
        .errnz  Low XMIN_2DECODE
        outwQ   XMIN,ax                           ; set up scissor rectangle
        Mov     Ax,xMax
        Dec     Ax
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX,Ax
        mov     ax,yMin
        or      ah,High YMIN_2DECODE
        .errnz  Low YMIN_2DECODE
        outwQ   YMIN,ax
        Mov     Ax,yMax
        Dec     Ax
        Or      Ah,High YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX,Ax
endm


setlimits macro cx,cy
        WaitQ   2                                 ; need room in the queue
        mov     ax,cx
        dec     ax
        outwQ   LX,ax                             ; 0-based width of the save area
        mov     ax,cy
        dec     ax
        outwQ   LY,ax                             ; 0-based height of a save area
        .errnz  LY_2DECODE
endm

copyrect macro  xD,yD,xS,yS
        WaitQ   2
        Mov     Al,0ffh                           ; read/write to/from all planes
        outbQ   READ_ENABLE,Al
        outbQ   WRITE_ENABLE,Al
        WaitQ   7
        outwQ   X0,xS                             ; ul of source area
        outwQ   Y0,yS
        outwQ   X1,xD                             ; send out destination x coordinate
        outwQ   Y1,yD                             ; send out destination y coordinate
        outbQ   FUNCTION_1,(FUNC_2OP_COPY+FUNC_S); straight replace mode
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_WSAVE               ; command to restore save area
endm

        assumes Ds,PtrData
        assumes Es,nothing

cProc   draw_pointer,<NEAR,PUBLIC,NO_ATTRPROF>
        parmW   ptsX
        parmW   ptsY
        localW  xInter
        localW  yInter
        localW  cxInter                          ; Width of work intersection
        localW  cyInter                          ; Height of work intersection
        localW  xDelta                           ; X delta of mouse movement
        localW  yDelta                           ; Y delta of mouse movement
        localW  xNewInWork                       ; X of new mouse coordinate in work area
        localW  yNewInWork                       ; Y of new mouse coordinate in work area
        localW  xNewInScreen                     ; X of new mouse coordinate on screen
        localW  yNewInScreen                     ; Y of new mouse coordinate on screen
cBegin

;/*
;** do the 8514 mapping (needed here especially when x is negative!)
;*/
        mov     ax,ptsX
        mov     bx,ptsY
        call    map_xy                            ; map it here
        mov     ptsX,ax                           ; save it locally
        mov     ptsY,bx

;/*
;** Set clipping to the max we'll need here
;*/
        mov     bx,PtrPatCacheY                   ; Cursors are right above PatCache
ifdef VIEW_MASKS                                  ; see map in 8514memd.asm
        mov     bx,768
endif
        setclip 0,0,Ptr_sd_cx,bx

        CPUMode 386

;/*
;** if there is no cursor on the screen then do some setup
;*/

        xor     al,al                             ; invalidation value
        .errnz  OLD_IS_INVALID
        xchg    al,old_valid                      ; invalidate, fetch previous flag

        or      al,al
        jz      set_no_deltas                     ; the is no pointer to remove

        cmp     cxPointer,40                      ; if the bitmap bigger than 40x40
        jg      set_no_deltas                     ; there is no room in the work area
        cmp     cyPointer,40
        jg      set_no_deltas

public  screen_to_work
screen_to_work:

;/*
;** copy the area around the new cursor position to the work area
;** this area is the union of the new pointer area and the old pointer
;** area (if the two areas intersect)
;*/

        mov     ax,ptsX
        sub     ax,old_x_cell                     ; ax = X delta of pointer move
        cmp     ax,cxPointer                      ; did they intersect?
        jge     no_intersect
        mov     cxInter,ax
        mov     dx,old_x_cell
        neg     ax
        js      short get_x                       ; was delta pos
        cmp     ax,cxPointer
        jge     no_intersect
        CPUMode 286

;/*
;** the new and old positions intersect; find that intersection
;*/

        mov     dx,ptsX
        mov     cxInter,ax

get_x:  mov     xDelta,ax                         ; dx = min X; ax = -X delta
        mov     xInter,dx
        mov     dx,cxPointer
        add     cxInter,dx                        ; add in delta

        mov     ax,ptsY
        sub     ax,old_y_cell                     ; ax = Y delta of pointer move
        cmp     ax,cyPointer                      ; did they intersect?
        CPUMode 386
        jge     no_intersect
        mov     cyInter,ax
        mov     dx,old_y_cell
        neg     ax
        js      get_y                             ; was delta pos
        cmp     ax,cyPointer
        jl      @F
        CPUMode 286

public  no_intersect
no_intersect:

;/*
;** erase old pointer area (if here it can't be all done in one shot)
;*/
        setlimits   cxPointer,cyPointer

;/*
;** erase current pointer
;*/
        copyrect    old_x_cell,old_y_cell,save_x_cell,save_y_cell

set_no_deltas:

;/*
;** fill in the work area with the new pointer
;*/
        setlimits   cxPointer,cyPointer
        copyrect    workptr_x_cell,workptr_y_cell,ptsX,ptsY

        mov     ax,cxPointer
        mov     cxInter,ax
        mov     ax,cyPointer
        mov     cyInter,ax
        mov     xDelta,0
        mov     yDelta,0

        mov     ax,ptsX
        mov     xNewInScreen,ax
        mov     ax,ptsY
        mov     yNewInScreen,ax
        jmp     work_to_save

;/*
;** the new and old positions intersect; find that intersection
;*/

@@:     mov     dx,ptsY
        mov     cyInter,ax

get_y:  mov     yDelta,ax                         ; dx = min Y; ax = -Y delta
        mov     yInter,dx
        mov     dx,cyPointer
        add     cyInter,dx                        ; add in delta

;/*
;** copy from screen to work area new area TO BE obscured by new pointer position
;*/

        setlimits   cxInter,cyInter
        mov     bx,ptsX
        cmp     xDelta,0
        jg      @F
        add     bx,xDelta
@@:     mov     xNewInScreen,bx
        mov     cx,ptsY
        cmp     yDelta,0
        jg      @F
        add     cx,yDelta
@@:     mov     yNewInScreen,cx
        copyrect    workptr_x_cell,workptr_y_cell,bx,cx

public  save_to_work
save_to_work:

;/*
;** new make the work area complete by filling in where the pointer used to be
;*/

        setlimits   cxPointer,cyPointer

        mov     bx,workptr_x_cell
        cmp     xDelta,0
        jl      @F
        add     bx,xDelta
@@:
        mov     cx,workptr_y_cell
        cmp     yDelta,0
        jl      @F
        add     cx,yDelta
@@:
        copyrect    bx,cx,save_x_cell,save_y_cell


public  work_to_save
work_to_save:

;/*
;** the work area now contains the intersection of the old pointer position
;** area and the new position area with valid screen.  Copy the area new cursor
;** position will obscure to the save area
;*/

        mov     bx,workptr_x_cell
        cmp     xDelta,0
        jg      @F
        sub     bx,xDelta
@@:     mov     xNewInWork,bx
        mov     cx,workptr_y_cell
        cmp     yDelta,0
        jg      @F
        sub     cx,yDelta
@@:     mov     yNewInWork,cx
        copyrect    save_x_cell,save_y_cell,bx,cx


;/*
;** apply the AND mask to the rectangle on the screen that will be
;** receiving the pointer image
;**
;** Issue a copy rectangle command. The source will be the monochrome AND
;** mask. The destination will be the color framebuffer at the new pointer
;** location.
;**
;** Note:  For color pointers we do the XOR mask first, then the AND mask.
;*/

public  mask1_to_work
mask1_to_work:

        WaitQ   1                                 ; need room in the queue
        outbQ   READ_ENABLE,READ_PLANE_0 ; read from just the 0th plane

;/*
;** LX and LY only need to be set once for all these commands we do here.
;** Currently:
;**       LX is set to cxPointer - 1               ; 0-based width  of the pointer
;**       LY is set to cyPointer - 1               ; 0-based height of the pointer
;*/

        WaitQ   8
        test    fbPointer,FBPTR_COLOR
        jnz     dp_color_ptr
        outwQ   X0,and_x_cell                     ; ul of AND mask
        outwQ   Y0,and_y_cell
        outbQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_ZEROS); AND the mask
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_D); AND the mask
        ??Qouts = ??Qouts - 4                     ; See def of WaitQ and outwQ in 8*.inc
        jmp     short   mono_ptr_handled
dp_color_ptr:
        outwQ   X0,xor_x_cell                     ; ul of XOR mask
        outwQ   Y0,xor_y_cell
        outbQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_D); XOR the mask
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_ND); XOR the mask
mono_ptr_handled:
        outwQ   X1,xNewInWork                     ; send out destination x coordinate
        outwQ   Y1,yNewInWork                     ; send out destination y coordinate
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_WMASK              ; command to write mask

;/*
;**  apply the XOR mask to the rectangle on the screen that will be receiving
;**  the pointer image
;** 
;**  Issue a copy rectangle command. The source will be the monochrome XOR
;**  mask. The destination will be the color framebuffer at the new pointer
;**  location.
;** 
;**  We make use of the fact that many of the adapter registers have already
;**  been setup in the blt above.
;** 
;**  Note:  For color pointers we did the XOR mask first, and now we will
;**         do the AND mask.
;** 
;**  Note on FUNCTION regs:  You'll notice we do different ROPs for
;**        functions 0 and 1, but that it gives us XOR nevertheless.
;**        So why don't we just use XOR for the rop on both function
;**        0 and 1?  That is because our source is mono and that so the
;**        result would be "0" expands to color 0 and "1" expands to color 1
;**        before the logical operation takes place.  But what we want is
;**        "1" to expand to all 1's and "0" to expand to all zeros.
;*/

public  mask2_to_work
mask2_to_work:

        WaitQ   7                                 ; need room in the queue
        test    fbPointer,FBPTR_COLOR
        jnz     dp_color_pointer
        outwQ   X0,xor_x_cell                     ; ul of XOR mask
        outwQ   Y0,xor_y_cell
        outbQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_D); XOR the mask
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_ND); XOR the mask
        ??Qouts = ??Qouts - 4                     ; See def of WaitQ and outwQ in 8*.inc
        jmp     short   mono_pointer_handled
dp_color_pointer:
        outwQ   X0,and_x_cell                     ; ul of AND mask
        outwQ   Y0,and_y_cell
        outbQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_ZEROS); AND the mask
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_D); AND the mask
mono_pointer_handled:
        outwQ   X1,xNewInWork                     ; send out destination x coordinate
        outwQ   Y1,yNewInWork                     ; send out destination y coordinate
        outwQ   CMD_FLAGS,CMD_WMASK               ; command to write mask

        test    fbPointer,FBPTR_COLOR
        jz      work_to_screen

;/*
;** Color Pointer
;**
;** We have a color pointer.  This consists of the two masks (AND and XOR)
;** just copied and a color bitmap.  Whereever the AND mask is "1" we draw
;** the bitmap.  Wherever the AND mask is "0" we do LEAVEALONE (transparent)
;** if the XOR mask is "0"; we do "dest invert" if the XOR mask is "1":
;**
;**   XOR    AND    Result
;**   ---    ---    ------
;**    0      0     use color bitmap
;**    1      0     use color bitmap
;**    0      1     transparent (screen leave alone)
;**    1      1     invert      (invert screen)
;**
;** By doing the XOR before the AND we have now set all the screen bits
;** as we want them.  We have "0"s where the bitmap will go.  The bitmap
;** image has been pre-processed so that it has "0"s where it will not be
;** used.  Thus we can simply "OR" the bitmap onto the screen.
;**
;** We make use of the fact that many of the adapter registers have already
;** been setup in the blts above.
;**
;** Issue a copy rectangle command. The source will be the color bitmap.
;** The destination will be the color framebuffer at the new pointer
;** location.
;*/

CMD_MCOLOR      =       (\
                         CMD_C_CRECT+CMD_FV_FIX+CMD_DX+\
                         CMD_DY+CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW\
                        )
public color_to_work
color_to_work:
        WaitQ   6                                 ; need room in the queue
        outbQ   READ_ENABLE,READ_ALL_PLANES      ; reading color bitmap
        outwQ   X0,clrptr_x_cell                 ; starting x of color pointer cache
        outwQ   Y0,clrptr_y_cell                 ; starting y of color pointer cache
        outwQ   X1,xNewInWork                     ; send out destination x coordinate
        outwQ   Y1,yNewInWork                     ; send out destination y coordinate
        WaitQ   4                                 ; need room in the queue
        outbQ   FUNCTION_1,(FUNC_2OP_COPY+FUNC_S_OR_D) ; OR the bitmap
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_MCOLOR             ; command to write it

public work_to_screen
work_to_screen:

        setclip     0,0,Ptr_sd_cx,Ptr_sd_cy
        setlimits   cxInter,cyInter
        copyrect    xNewInScreen,yNewInScreen,workptr_x_cell,workptr_y_cell

dp_mono_ptr_done:

;/*
;** map the x_cell and y_cell values into an 8514/A x,y
;*/

        mov     ax,ptsX
        mov     old_x_cell,ax                           ; save it locally
        mov     ax,ptsY
        mov     old_y_cell,ax
        mov     old_valid,OLD_IS_VALID                  ; save area contains valid bits

cEnd
page


;/***************************************************************************
;*
;* FUNCTION NAME = pointer_off 
;*
;* DESCRIPTION   = The old pointer is removed from the screen if it currently 
;*                 is on the screen.  
;*                                                                          
;*                 Registers Preserved:
;*                       BP,DS
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,ES,FLAGS
;*
;*                 Restrictions:
;*                     fGrimReaper must have been checked prior
;*                     to calling this routine.
;*
;* INPUT         = DS = PtrData 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

;/*
;** compose 8514/A command to write back the save area
;*/

CMD_WRESTORE    =       CMD_WSAVE

        assumes ds,PtrData
        assumes es,nothing

cProc   pointer_off,<NEAR,PUBLIC,NO_ATTRPROF>
cBegin  <nogen>


;/*
;** make sure there is an old cursor to remove
;*/

        Sub     Al,Al                             ; invalidation value
        .errnz  OLD_IS_INVALID
        Xchg    Al,old_valid                      ; invalidate, fetch previous flag

        Or      Al,Al
        jnz     @F                                ; we have a cursor to remove...
        Jmp     pointer_off_end                   ; no cursor to remove...
@@:

;/*
;** Copy the contents of the save buffer back to the location in the framebuffer
;** from which it was taken
;**
;** Issue a copy rectangle command. The source will be the bits currently
;** in the save buffer. The destination will be the spot in the framebuffer
;** from which the bits originally were taken.
;*/

        WaitQ   8                                 ; need room in the queue
        outwQ   XMIN,(XMIN_2DECODE+0)             ; set up scissor rectangle
        Mov     Ax,Ptr_sd_cx
        Dec     Ax
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX,Ax
        outwQ   YMIN,(YMIN_2DECODE+0)
        Mov     Ax,Ptr_sd_cy
        Dec     Ax
        Or      Ah,High YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX,Ax
        Mov     Al,0ffh                           ; read/write to/from all planes
        outbQ   READ_ENABLE,Al
        outbQ   WRITE_ENABLE,Al
        mov     ax,cxPointer
        dec     ax
        outwQ   LX,ax                             ; 0-based width of the save area
        mov     ax,cyPointer
        dec     ax
        outwQ   LY,ax                             ; 0-based height of a save area
        .errnz  LY_2DECODE

        WaitQ   7
        outwQ   X0,save_x_cell                    ; ul of save area
        outwQ   Y0,save_y_cell
        outwQ   X1,old_x_cell                     ; send out destination x coordinate
        outwQ   Y1,old_y_cell                     ; send out destination y coordinate
        outbQ   FUNCTION_1,(FUNC_2OP_COPY+FUNC_S); straight replace mode
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_WRESTORE           ; command to restore save area

pointer_off_end:

        Ret
cEnd    <nogen>

        page
;/***************************************************************************
;*
;* FUNCTION NAME = map_xy
;*
;* DESCRIPTION   = 
;*
;*        Map X,Y into hw X,Y
;*
;*        The given screen (x,y) coordinate is mapped to an (x,y) coordinate
;*        according to the way in which the hardware wants to see it.
;*
;*                 Registers Preserved:                                                       
;*                       DX,SI,DI,BP,ES,DS                                                    
;*                 Registers Destroyed:                                                       
;*                       AX,BX,CX,FLAGS                                                       
;*
;* INPUT         = AX = screen x coordinate
;*                 BX = screen y coordinate
;*                 DS = PtrData
;* OUTPUT        = AX = swizzled to hw x coordinate
;*                 BX = swizzled to hw y coordinate
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,PtrData
        assumes Es,nothing

        Public  map_xy
map_xy  Proc    Near

;/*
;** Are we running in the 512 line mode ? If we are, we must swizzle the y
;** coordinate such that bits 1-11 (bits 12-15 are irrelevant here) are shifted
;** up 1 bit, and the now vacated bit 1 must be ensured to be reset.
;**
;** Rational weighting:
;**
;**       Bit:    11  10   9   8   7   6   5   4   3   2   1   0
;**    Weight:     0  xx  512 256 128  64  32  16  8   4   2   1
;**
;** Swizzled weighting:
;**
;**       Bit:    11  10   9   8   7   6   5   4   3   2   1   0
;**    Weight:     0  512 256 128  64  32  16  8   4   2   0   1
;*/

        Test    Ptr_hwFlags,HW_MON_640           ; 512 line mode ?
        Jz      @F                                ; no...

;/*
;** swizzle y coordinate
;*/

        Shr     Bx,1                              ; preserve low bit
        Sbb     Cl,Cl                             ; in this spot
        Sal     Bx,1                              ; bit 0 reset, will become bit 1
        Shr     Cl,1                              ; get back bit 0
        Rcl     Bx,1                              ; and restore it to rightful place
@@:

;/*
;** are the coordinates negative ? If they are, we must swizzle them so that
;** the low order 9 bits specify a positive offset from some negative minimum
;** (-256 or -512 for 640x480 and 1kx768 modes respectively).
;*/

;/*
;** check the x coordinate
;*/

        Or      Ax,Ax
        Jns     @F                                ; x coordinate is in range

;/*
;** swizzle the x coordinate
;*/

        And     Ax,0000000111111111b              ; isolate low order bits
        Or      Ah,High XY_NEG                    ; add in negative indicator
        .errnz  Low XY_NEG
@@:

;/*
;** check the y coordinate
;*/

        Or      Bx,Bx
        Jns     @F                                ; y coordinate is in range

;/*
;** swizzle the y coordinate
;*/

        And     Bx,0000000111111111b              ; isolate low order bits
        Or      Bh,High XY_NEG                    ; add in negative indicator
        .errnz  Low XY_NEG
@@:

        Ret
map_xy  Endp

sEnd    Code

        End
