;*DDK*************************************************************************/
;
; 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.;
;*****************************************************************************/

;/*****************************************************************************
;*
;* SOURCE FILE NAME = POINTER2.ASM
;*
;* DESCRIPTIVE NAME = More pointer related functions.
;*
;*
;* VERSION      V2.0
;*
;* DATE         10/25/91
;*
;* DESCRIPTION  More pointer related functions.
;*
;* FUNCTIONS    CreateMasks1Thru7
;*              move_pointers
;*
;*
;* 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/01/93               60688  Clear cursor ( all 1's AND mask and all 0's XOR mask )
;*                                                        leaving trails on screen
;*****************************************************************************/

;/*
;** Include files
;*/

        .386P
        .MODEL FLAT,SYSCALL

INCL_GPIPRIMITIVES EQU 1
INCL_NOBASEAPI     EQU 1
INCL_SAADEFS       EQU 1
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC
DINCL_BITMAP EQU 1
DINCL_ENABLE EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC

        INCLUDE EGAFAM.INC
        INCLUDE POINTER.INC
        INCLUDE ASSERT.MAC
        INCLUDE CURSORS.INC
        include curstrc.inc
.DATA
EXTERNDEF CurData:CURSORSTRUCT
.CODE
_TUNE segment USE32 PUBLIC 'CODE'
        SUBTITLE CreateMasks1Thru7
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = CreateMasks1Thru7
;*
;* DESCRIPTION   =
;*        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|
;*
;*       Registers Preserved:
;*             BX,SI,DS,ES,BP
;*       Registers Destroyed:
;*             AX,CX,DX,DI
;*
;* INPUT         = 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 FFh)
;*
;* OUTPUT        = EDI --> First byte following end of mask for phase alignment 1
;*                 EDX --> First byte following end of mask for phase alignment 0
;*                 ECX  =  0
;*                 EAX  =  Unknown
;*
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        ALIGN   4

CreateMasks1Thru7 PROC SYSCALL PRIVATE

;/*
;** 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

        RET

CreateMasks1Thru7 ENDP
        SUBTITLE move_pointers
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = move_pointers
;*
;* DESCRIPTION   =
;*   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.
;*
;*       Registers Preserved:
;*             BP
;*       Registers Destroyed:
;*             AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* INPUT         = C Prototype:
;*                   ULONG move_pointers (ULONG  pBitsAndXor,
;*                                        ULONG  pBitsColor,
;*                                        USHORT wFlags);
;*
;*                    where:
;*                      pBitsAndXor points to the AND/XOR masks.
;*                      pBitsColor  points to the color mask.
;*                      wFlags      indicates the type of pointer and is one of
;*                                  the  following:
;*                                    FBPTR_COLOR if color pointer
;*                                    0           if mono pointer
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 32-bit value consisting of two 16-bit fields.  The
;*                 high-order word contains the height in scan lines to be
;*                 used for the exclusion hit test, while the low-order word
;*                 contains the width in pels to be used for the exclusion
;*                 hit test.
;*
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4

move_pointers PROC SYSCALL PUBLIC uses EBX ECX EDX EDI ESI,
                pBitsAndXor:DWORD,
                pBitsColor :DWORD,
                fwFlags    :DWORD

        CLD

;/*
;** 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 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.
;*/

;/*
;** 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     CurData.fbPointer,0             ; Assume it's a b/w pointer
        LEA     EDI,CurData.BaseAndMasks
        MOV     ECX,PTR_HEIGHT                  ; Set height for move
        MOV     EBX,0FFFFFFFFh                  ; Init. mask column accum.
        MOV     ESI,pBitsAndXor                 ; ESI --> AND/XOR mask

Move_next_AND_mask_scan:
        LODSD                                   ; Move explicit part
        STOSD
        AND     EBX,EAX                         ; Accumulate columns
        MOV     AL,0FFh                         ; Set extra byte for row
        STOSB
        .ERRNZ  PTR_WIDTH-4
        .ERRNZ  WORK_WIDTH-5
        LOOP    Move_next_AND_mask_scan
        PUSH    EBX                             ; Save AND column mask
        LEA     EDX,CurData.BaseAndMasks         ; EDX --> BaseAndMasks
        MOV     ECX,(MASK_LENGTH*7)/(WORK_WIDTH*2)
        .ERRNZ  (MASK_LENGTH*7) MOD (WORK_WIDTH*2)
        INVOKE  CreateMasks1Thru7

;/*
;** 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     ECX,PTR_HEIGHT          ; Set height for move
        XOR     EBX,EBX                 ; Init column mask accumulator

Move_next_XOR_mask_scan:
        LODSD                           ; Move explicit part
        STOSD
        OR      EBX,EAX                 ; Accumulate column mask
        XOR     AL,AL                   ; Set extra byte
        STOSB
        .ERRNZ  PTR_WIDTH-4
        .ERRNZ  WORK_WIDTH-5
        LOOP    Move_next_XOR_mask_scan
        LEA     EDX,CurData.BaseXorMasks
        MOV     ECX,(MASK_LENGTH*7)/(WORK_WIDTH*2)
        .ERRNZ  (MASK_LENGTH*7) MOD (WORK_WIDTH*2)
        INVOKE  CreateMasks1Thru7

;/*
;** 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     EAX                     ; EAX = AND mask
                                        ; EBX = XOR 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
        TEST    fwFlags,PTRI_ANIMATE    ; Force full mask if doing animation
        JNZ     mp_have_sizes
;*
;*  Begin            60688
;*
;        movZX   edx,ax                  ;DX = bytes 1 and 2
;        shr     eax,16                  ;AX = bytes 3 and 4
;        or      ah,ah                   ;Discard 4th byte of mask?
;        jnz     @F                      ;  No
;        dec     ebx
;        or      al,al
;        jnz     @F
;        dec     ebx
;        or      dh,dh
;        jnz     @F
;        dec     ebx
;        or      dl,dl
;        jz      move_pointers_done      ;AX = DX = 0 for return codes
;*
;* End            60688
;*
@@:

;/*
;** 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     eax,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      @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                      ;CX = working height
        mov     edx,PTR_HEIGHT
        sub     edx,ecx                   ;DX = # scans chopped off bottom
        xchg    ecx,edx                   ;Height in DX for returning

;/*
;** BX = working width of the pointer image in bytes.  CX = amount to
;** chop of the bottom of the pointer image.  DX = working height of
;** the pointer image.
;*/

mp_have_sizes:
        mov     eax,ebx
        mov     CurData.sizsMask.sizs_cx,ax
        mov     CurData.sizsMaxDelta.sizs_cx,ax
        mov     ah,dl
        mov     CurData.sizbMask,ax
        .errnz  SIZEB.sizb_cy-SIZEB.sizb_cx-1
        mov     eax,edx
        mov     CurData.sizsMask.sizs_cy,ax
        mov     CurData.sizsMaxDelta.sizs_cy,ax
        neg     eax
        add     eax,SCREEN_CY
        mov     CurData.ptlBotRightClip.ptl_y,eax
        mov     eax,SCREEN_CBSCAN
        sub     eax,ebx
        mov     CurData.ptlBotRightClip.ptl_x,eax
        shr     ecx,1
        mov     eax,WORK_WIDTH
        sub     eax,ebx
        shr     eax,1
        mov     ah,cl
        mov     CurData.ptbInitOrigin,ax
        .errnz  POINTB.ptb_y-POINTB.ptb_x-1
        mov     eax,ebx
        dec     eax
        shl     eax,3                    ;Bit count is needed

        push    edx                      ;Remember return values
        push    eax

;/*
;** 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          ;Set DS:SI --> color bitmap bits
        jecxz   move_color_pointer_done ;pBitsColor.sel was set to zero
        mov     esi,ecx
        LEA     edi,CurData.BaseColorMasks
        push    ebp                      ;Need extra loop counter
        mov     ebp,BITS_PEL

move_next_color_mask_plane:
        mov     ecx,PTR_HEIGHT           ;Set height for move
        LEA     ebx,CurData.BaseAndMasks
        sub     ebx,edi                   ;make it relative

move_next_color_mask_scan:

        movsw
        movsw


        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     move_next_color_mask_plane
        pop     ebp                      ;Restore register

        LEA     edx,CurData.BaseColorMasks
        mov     ecx,(CLR_MASK_LENGTH*7)/(WORK_WIDTH*2)
        .errnz  (CLR_MASK_LENGTH*7) mod (WORK_WIDTH*2)
        INVOKE  CreateMasks1Thru7
        mov     CurData.fbPointer,FBPTR_COLOR   ;Indicate color pointer

move_color_pointer_done:

        pop     eax                      ;return results in DX,AX
        pop     edx

move_pointers_done:
        ret
move_pointers ENDP
_TUNE ENDS
        END

