File:  [WindowsNT SDKs] / ntddk / src / video / displays / vga / i386 / rleblts.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

;---------------------------Module-Header------------------------------;
; Module Name: rleblts.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
        .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 cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        assume fs:nothing,gs:nothing

        .xlist
        include stdcall.inc             ;calling convention cmacros
        include i386\egavga.inc
        include i386\strucs.inc
        .list

        .code

;-------------------------------Macro-----------------------------------;
; RleSetUp
;
;   Set the EGA\VGA to write mode 2 (M_COLOR_WRITE).  Initialize local vars
;
; Entry:
;       None
; Returns:
;       ESI = pointer to the source bitmap
;
;-----------------------------------------------------------------------;

RleSetUp    macro

        cld

        mov     dx,VGA_BASE + GRAF_ADDR
        mov     ax,(M_COLOR_WRITE shl 8) + GRAF_MODE
        out     dx,ax

        mov     esi,pRleInfo
        mov     edi,[esi].RLE_prctlTrg
        mov     eax,[edi].xLeft
        mov     xStart,eax
        mov     eax,[esi].RLE_xBegin
        mov     xCurr,eax
        mov     eax,[edi].yBottom
        dec     eax
        mov     yCurr,eax

        mov     eax,[esi].RLE_pulTranslate
        mov     pulXlate,eax
        mov     eax,[esi].RLE_prctlClip
        mov     prclClip,eax
        mov     eax,[esi].RLE_pjSrcBitsMax
        mov     pjSrcEnd,eax
        mov     ebx,[esi].RLE_pjTrg

        mov     pjDst,ebx
        mov     esi,[esi].RLE_pjSrcBits
endm

;-------------------------------Macro-----------------------------------;
; RleDelta
;
;   Handle the Delta case.
;
; Entry:
;       ESI = pointer to the horz/vert offset of the source bitmap
; Returns:
;       None
;
;-----------------------------------------------------------------------;

RleDelta    macro   dest

        lodsw
        movzx   ecx,al
        add     xCurr,ecx               ;x adjustment

        movzx   eax,ah
        sub     yCurr,eax               ;y adjustment

        mul     lNextScan
        sub     pjDst,eax
        jmp     dest
endm

;-------------------------------Macro-----------------------------------;
; RleExit
;
;   Prepare the Rle routine to exit.  Set the EGA/VGA to default write
;   mode.  Save the current status in the RleInfo so we can continue
;   from where we left off if a complex clipping is encountered.
;
; Entry:
;       ESI = pointer pass the first run above the clipping rect
;       EBX = yCurr(y value of the first run above the clipping rect)
;       ECX = xCurr(x value of the first run above the clipping rect)
; Returns:
;       None
;
;-----------------------------------------------------------------------;

RleExit macro

        mov     dx,VGA_BASE + GRAF_ADDR
        mov     ax,(M_PROC_WRITE shl 8) + GRAF_MODE
        out     dx,ax

        mov     ax,0FF00h + GRAF_BIT_MASK
        out     dx,ax                   ;no mask

        mov     edi,pRleInfo            ;update for next call
        dec     esi
        dec     esi
        mov     [edi].RLE_pjSrcBits,esi
        mov     esi,[edi].RLE_prctlTrg
        inc     ebx                     ;make it exclusive
        mov     [esi].yBottom,ebx
        mov     eax,pjDst
        mov     [edi].RLE_pjTrg,eax
        mov     [edi].RLE_xBegin,ecx
endm

;-------------------------------Macro-----------------------------------;
; Clip_Encoded
;
;   Clip the current run in encoded mode against the clipping rect.
;
; Entry:
;       AH = pel color of this run
;       AL = number of pels of this run
; Returns:
;       EAX = left coordinate if no clipping
;       ECX = left coordinate of the clipped run
;       EBX = right coordinate of the clipped run
;
;-----------------------------------------------------------------------;

Clip_Encoded    macro   done, loop_start

        movzx   edx,ah                  ;EDX = pel color
        movzx   eax,al                  ;EAX = number of pels
        mov     ecx,xCurr               ;ECX = left coordinate
        add     xCurr,eax               ;compute new x position
        mov     ebx,yCurr

; Check if y is inside the clipping range.

        mov     edi,prclClip
        cmp     ebx,[edi].yTop
        jb      done
        cmp     ebx,[edi].yBottom
        jae short loop_start

; Clip to the passed in clip rectangle.

        mov     eax,ecx
        cmp     ecx,[edi].xLeft
        jae short @F
        mov     ecx,[edi].xLeft

@@:
        mov     ebx,xCurr
        cmp     ebx,[edi].xRight
        jbe short @F
        mov     ebx,[edi].xRight

@@:
        cmp     ebx,ecx                 ;clipped out if left and right crossed
        jbe short loop_start
endm

;-------------------------------Macro-----------------------------------;
; Draw_Encoded
;
;   Write the current encoded run to the EGA/VGA.
;
; Entry:
;       EBX = right coordinate (exclusive)
;       ECX = left coordinate  (inclusive)
;       EDX = pel color
; Returns:
;       None
;
;-----------------------------------------------------------------------;

Draw_Encoded    macro   loop_start

        call    comp_masks              ;compute bit masks

        shl     eax,8                   ;save right mask in high word
        add     edi,pjDst

        mov     ebx,pulXlate
        mov     ebx,[ebx][edx*4]

        mov     dx,VGA_BASE + GRAF_ADDR

        or      ah,ah                   ;AH = left mask
        jz short @F

        mov     al,GRAF_BIT_MASK        ;Set bitmask for altered bits
        out     dx,ax

        mov     al,bl                   ;write color
        xchg    [edi],al
        inc     edi                     ;update destination pointer

@@:
        or      ecx,ecx                 ;ECX = inner loop count
        jz short @F

        mov     ax,0FF00h + GRAF_BIT_MASK
        out     dx,ax                   ;no mask

        mov     al,bl
        rep     stosb                   ;write color

@@:
        shr     eax,8                   ;AH = right mask
        or      ah,ah
        jz      loop_start

        mov     al,GRAF_BIT_MASK        ;Set bitmask for altered bits
        out     dx,ax
        xchg    [edi],bl                ;write color

        jmp     loop_start
endm

;-------------------------------Macro-----------------------------------;
; Clip_Absolute
;
;   Clip the current run in absolute mode against the clipping rect.
;   Compute initial bit mask and other vars for subsequent loop.
;
; Entry:
;       AH = number of pels of this run
; Returns:
;       AL = GRAF_BIT_MASK
;       AH = bitmap for the first pel
;       EBX = pulXlate (pointer to the xlate table)
;       CH = 01000001b
;       EDI = pointer to destination byte to be altered
;       loop_count = loop count (number of pels to be altered)
;
;-----------------------------------------------------------------------;

Clip_Absolute   macro   done,loop_end,loop_count

        movzx   eax,ah                  ;EAX = number of pels
        mov     ecx,xCurr               ;ECX = left coordinate
        add     xCurr,eax

        mov     ebx,yCurr

; Check if y is inside the clipping range.

        mov     edi,prclClip
        cmp     ebx,[edi].yTop
        jb      done
        cmp     ebx,[edi].yBottom
        jae     loop_end

; Check if x is inside the clipping range.

        cmp     ecx,[edi].xRight        ;check if x is in range
        jae     loop_end

        mov     ebx,xCurr               ;EBX = right coordinate
        cmp     ebx,[edi].xLeft         ;can I not jump???!!!
        jbe     loop_end

; Clip to the passed in clip rectangle.

        cmp     ecx,[edi].xLeft
        mov     cPreSrcAdv,0
        jae short @F
        mov     eax,[edi].xLeft
        sub     eax,ecx                 ;diff of left coor and prclClip->xLeft
        mov     cPreSrcAdv,eax
        add     ecx,eax                 ;ECX = left coordinate = prclClip->xLeft

@@:
        xor     eax,eax                 ;diff of right coor and prclClip->xRight
        cmp     ebx,[edi].xRight
        jbe short @F
        mov     eax,ebx
        mov     ebx,[edi].xRight        ;EBX = right coor = prclClip->xRight
        sub     eax,ebx

@@:
        mov     cPostSrcAdv,eax
        sub     ebx,ecx                 ;loop count

        mov     edi,ecx
        shr     edi,3
        add     edi,pjDst               ;point to the first byte to write

        and     ecx,00000111b           ;Compute bit index for left side
        mov     ah,080h                 ;Compute bit mask
        shr     ah,cl                   ;AL = first pel bit mask
        mov     al,GRAF_BIT_MASK
        mov     loop_count,bl           ;loop count < 0FFh
        mov     ch,01000001b            ;for later use
        mov     ebx,pulXlate
endm

;-------------------------------Macro-----------------------------------;
; RleEOL
;
;   Handle the End of line case.
;
; Entry:
;       None.
; Returns:
;       None.
;
;-----------------------------------------------------------------------;

RleEOL  macro   loop_start

        mov     eax,lNextScan
        sub     pjDst,eax               ;adjust pjDst
        dec     yCurr                   ;adjust yCurr
        mov     eax,xStart              ;adjust xCurr
        mov     xCurr,eax
        jmp     loop_start
endm


;-------------------------------Macro-----------------------------------;
; Set up banking-related variables, and make sure the bank for the
; initial (bottom) scan line is mapped in.
;
; Entry:
;       None.
; Returns:
;       EBX = pdsurf
;       ESI = pRleInfo
;       EDI = RLE_prctlClip
;
;-------------------------------Macro-----------------------------------;

RleBankSetUp macro
        local   map_bank,bank_mapped

        mov     esi,pRleInfo
        mov     ebx,[esi].Rle_pdsurfTrg
        mov     pdsurf,ebx

        mov     eax,[ebx].dsurf_lNextScan
        mov     lNextScan,eax

        mov     edi,[esi].RLE_prctlClip
        mov     eax,[edi].yTop
        mov     ulTrueClipTop,eax       ;we blt until we reach this scan line

; Map in the bottom scan line of the clip rect.

        mov     eax,[edi].yBottom       ;bottom clip scan, exclusive
        dec     eax                     ;make it inclusive
        cmp     eax,[ebx].dsurf_rcl1WindowClip.yTop
        jl      short map_bank
        cmp     eax,[ebx].dsurf_rcl1WindowClip.yBottom
        jl      short bank_mapped
map_bank:
        ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,eax,JustifyBottom>
bank_mapped:

        endm


;-------------------------------Macro-----------------------------------;
; Set up the screen pointer and clip the clip rect to the current bank.
;
; Entry:
;       EBX = pdsurf
;       ESI = pRleInfo
;       EDI = RLE_prctlClip
; Returns:
;       None.
;
;-------------------------------Macro-----------------------------------;

RleBankTop macro

; Convert the screen pointer from an offset within the bitmap to a virtual
; address.

        mov     eax,[ebx].dsurf_pvBitmapStart
        add     [esi].RLE_pjTrg,eax

; Set the clip rect top to MAX(top_of_bank,top_of_clip), to confine drawing to
; this bank.

        mov     eax,[ebx].dsurf_rcl1WindowClip.yTop
        cmp     ulTrueClipTop,eax
        jl      short @F
        mov     eax,ulTrueClipTop
@@:
        mov     [edi].yTop,eax

        endm


;-------------------------------Macro-----------------------------------;
; Check whether we've done the last bank spanned by this clip rect; exit
; if so, map in the bank and continue if not.
;
; Entry:
;       None.
; Returns:
;       EBX = pdsurf
;       ESI = pRleInfo
;       EDI = RLE_prctlClip
;
;-------------------------------Macro-----------------------------------;

RleBankBottom macro     loop_top,done

; Convert the screen pointer back to an offset within the bitmap.

        mov     ebx,pdsurf
        mov     esi,pRleInfo
        mov     eax,[ebx].dsurf_pvBitmapStart
        sub     [esi].RLE_pjTrg,eax

; Have we reached the top bank involved in this blt? If so, done; if not, map
; it in and blt the next bank.

        mov     eax,[ebx].dsurf_rcl1WindowClip.yTop
        cmp     eax,ulTrueClipTop
        jle     &done
        dec     eax     ;map in the bank above the current one
        ptrCall <dword ptr [ebx].dsurf_pfnBankControl>,<ebx,eax,JustifyBottom>

        mov     edi,[esi].RLE_prctlClip ;for RleBankTop

        jmp     &loop_top

        endm


;--------------------------Public-Routine-------------------------------;
; vRle8ToVga
;
;   Write an RLE8 bitmap onto the VGA device.
;
; Entry:
;       None.
; Returns:
;       None
;
;-----------------------------------------------------------------------;

cProc   vRle8ToVga,4,<       \
        uses    esi edi ebx,  \
        pRleInfo: ptr RLEINFO >

        local   pjDst       :ptr
        local   pulXlate    :ptr
        local   xCurr       :dword
        local   yCurr       :dword
        local   xStart      :dword
        local   cPreSrcAdv  :dword
        local   cPostSrcAdv :dword
        local   prclClip    :ptr RECTL
        local   pjSrcEnd    :ptr
        local   pdsurf      :ptr DEVSURF
        local   ulTrueClipTop :dword
        local   lNextScan   : dword

        RleBankSetUp    ;wrap a banking loop around everything

rle8_bank_loop:

        RleBankTop

        RleSetUp

rle8_loop:
        cmp     esi,pjSrcEnd
        jae     rle8_done
        lodsw                           ;fetch a word from src RLE bitmap

        or      al,al
        jz      rle8_escape

rle8_encoded:
        Clip_Encoded    rle8_done,rle8_loop
        Draw_Encoded    rle8_loop

rle8_escape:
        cmp     ah,2                    ; First byte is 0, check the second byte.
        ja      short rle8_absolute
        jb      rle8_end_of_line_or_bitmap

rle8_delta:
        RleDelta    rle8_loop

rle8_absolute:
        Clip_Absolute   rle8_done,rle8_absolute_advance_src,cl
        add     esi,cPreSrcAdv          ;advance esi to point to the clipped run

; I am doing a per pel loop rather than a per byte loop which writes 1 plane
; at a time because it appears to me that most of the time we output 2 or
; 3 pels per encounter of absolute mode.  The logic here is simple and we can
; stay with M_COLOR_WRITE mode all the time.

rle8_absolute_loop:
        mov     dx,VGA_BASE + GRAF_ADDR
        out     dx,ax                   ;Set bitmask for altered bit

        movzx   edx,byte ptr [esi]      ;grab color for this pel
        inc     esi

        mov     edx,[ebx][edx*4]
        xchg    [edi],dl                ;write to destination

        ror     ah,1                    ;rotate bit mask for next pel
        cmp     ch,ah                   ;cmp bitmask with 01000001b
        adc     edi,0                   ;advance edi if bitmask is 10000000b

        dec     cl                      ;per pel loop
        jnz short rle8_absolute_loop
        mov     eax,cPostSrcAdv

rle8_absolute_advance_src:
        add     esi,eax                 ;advance src ptr for clipped out pels
        bt      esi,0                   ;add 1 if not word aligned
        adc     esi,0
        jmp     rle8_loop

rle8_end_of_line_or_bitmap:
        or      ah,ah
        jnz short rle8_end_of_bitmap

rle8_end_of_line:

        RleEOL  rle8_loop

rle8_done:
        RleExit

        RleBankBottom   rle8_bank_loop,rle8_exit ;see if there are more banks
                                                 ; to do
        align   4
rle8_end_of_bitmap:
        RleExit
rle8_exit:
        cRet    vRle8ToVga

endProc vRle8ToVga


;--------------------------Public-Routine-------------------------------;
; vRle4ToVga
;
;   Write an RLE4 bitmap onto the VGA device.
;
; Entry:
;       None
; Returns:
;       None
;
;-----------------------------------------------------------------------;

cProc   vRle4ToVga,4,<       \
        uses    esi edi ebx,  \
        pRleInfo: ptr RLEINFO >

        local   pjDst       :ptr
        local   pulXlate    :ptr
        local   xCurr       :dword
        local   yCurr       :dword
        local   xStart      :dword
        local   cPreSrcAdv  :dword
        local   cPostSrcAdv :dword
        local   pjDstStart  :ptr
        local   iPels       :dword
        local   xMask       :dword
        local   nPels       :byte
        local   prclClip    :ptr RECTL
        local   pjSrcEnd    :ptr
        local   pdsurf      :ptr DEVSURF
        local   ulTrueClipTop :dword
        local   lNextScan   : dword

        RleBankSetUp    ;wrap a banking loop around everything

rle4_bank_loop:

        RleBankTop

        RleSetUp

rle4_loop:
        cmp     esi,pjSrcEnd
        jae     rle4_done
        lodsw                           ;fetch a word

        or      al,al
        jz      rle4_escape

rle4_encoded:
        Clip_Encoded    rle4_done,rle4_loop

        mov     dh,dl                   ;separate two colors into dl, dh
        and     dl,0Fh
        shr     dh,4
        cmp     dh,dl
        jnz short encoded_diff_color
        xor     dh,dh                   ;Draw_Encoded use edx as color index
        Draw_Encoded    rle4_loop

encoded_diff_color:
        sub     eax,ecx                 ;-eax = #pels clipped away
        bt      eax,0
        jnc short @F
        xchg    dl,dh                   ;xchg colors if odd #pels clipped
@@:
        mov     iPels,edx               ;save color index
        sub     ebx,ecx                 ;Compute extent of interval
        dec     ebx                     ;Make interval inclusive
        mov     edi,ecx                 ;Don't destroy starting X
        shr     edi,3                   ;/8 for byte address
        add     edi,pjDst

        and     ecx,00000111b           ;Compute bit index for first byte
        mov     eax,00AAAAAAh           ;Compute altered bits mask
        shr     eax,cl                  ;AL = left side altered bytes mask

        add     ebx,ecx                 ;Compute bit index for last byte
        mov     ecx,ebx                 ;(save for inner loop count)
        and     ecx,00000111b
        mov     ch,80h
        sar     ch,cl
        and     al,ch                   ;AL = last byte altered bits mask

        mov     edx,eax
        shr     edx,1
        and     dl,ch                   ;EDX = mask for 2nd pel

        mov     ecx,ebx
        shr     ecx,3                   ;Compute inner byte count
        jnz     short comp_byte_dont_combine ;loop count + 1 > 0, check it out

; Only one byte will be affected.  Combine first/last masks, set loop count = 0

        mov     ebx,eax
        shl     eax,16                  ;Will use first byte mask only
        and     eax,ebx                 ;AH = first mask. Rest of the bits = 0

        mov     ebx,edx
        shl     edx,16                  ;Will use first byte mask only
        and     edx,ebx                 ;DH = first mask. Rest of the bits = 0
        inc     ecx                     ;Fall through to set 0

comp_byte_dont_combine:
        dec     ecx                     ;Dec inner loop count (might become 0)

        xchg    al,ah
        ror     eax,16                  ;EAX = last mask:inter mask:first mask:0
        xchg    al,ah                   ;for first pel
        xchg    dl,dh
        ror     edx,16                  ;EDX = last mask:inter mask:first mask:0
        xchg    dl,dh                   ;for second pel

        mov     pjDstStart,edi
        mov     xMask,edx                ;save mask for the 2nd round

        mov     ebx,pulXlate
        mov     edx,iPels
        shr     edx,8                   ;index for the first pel
        mov     ebx,[ebx][edx*4]
        inc     bh                      ;BH = rle4_encoded_diff_color_loop count
        inc     bh
        mov     dx,VGA_BASE + GRAF_ADDR
                                        ;BL = color for first pel
rle4_encoded_diff_color_loop:
        or      ah,ah                   ;AH = first mask
        jz short encoded_inner_diff_color

        mov     al,GRAF_BIT_MASK        ;Set bitmask for altered bits
        out     dx,ax

        mov     al,bl
        xchg    [edi],al                ;write color
encoded_inner_diff_color:
        inc     edi                     ;update destination pointer
        shr     eax,8                   ;AH = internal mask
        or      cl,cl                   ;ECX = inner loop count
        jz short encoded_last_byte_diff_color

        mov     ch,cl                   ;save loop count in ch
                                        ;loop count always fit in a byte
        mov     al,GRAF_BIT_MASK
        out     dx,ax                   ;no mask

encoded_loop_diff_color:
        mov     al,bl
        xchg    [edi],al                ;write color
        inc     edi
        dec     cl
        jnz     encoded_loop_diff_color

encoded_last_byte_diff_color:
        shr     eax,8                   ;AH = last mask
        or      ah,ah
        jz      encoded_this_run_maybe_done

        mov     al,GRAF_BIT_MASK        ;Set bitmask for altered bits
        out     dx,ax

encoded_write:
        xchg    [edi],bl                ;write color

encoded_this_run_maybe_done:
        dec     bh
        jz      rle4_loop

        mov     edi,pulXlate
        mov     eax,iPels               ;index of the second pel
        xor     ah,ah
        mov     bl,byte ptr [edi][eax*4]
        mov     edi,pjDstStart
        mov     eax,xMask               ;load mask
        mov     cl,ch                   ;loop count

        jmp     rle4_encoded_diff_color_loop

rle4_escape:
        cmp     ah,2                    ; First byte is 0, check the second byte.
        ja      rle4_absolute
        jb      rle4_end_of_line_or_bitmap

rle4_delta:

        RleDelta    rle4_loop

rle4_absolute:
        Clip_Absolute   rle4_done,rle4_absolute_advance_src,nPels

;advance esi to point to the clipped run

        mov     edx,cPreSrcAdv          ;number of pels to advance
        shr     edx,1                   ;number of bytes
        jnc     @F

        add     esi,edx                 ;odd number of pels to advance
        movzx   edx,byte ptr [esi]      ;grab color for prev and this pels
        inc     esi
        mov     iPels,edx

        inc     nPels                   ;inc loop count since we start from 1
        mov     cl,1
        jmp short absolute_loop

@@:                                     ;even number of pels to advance
        add     esi,edx

; I am doing a per pel loop rather than a per byte loop which writes 1 plane
; at a time because it appears to me that most of the time we output 2 or
; 3 pels per encounter of absolute mode.  The logic here is simple and we can
; stay with M_COLOR_WRITE mode all the time.

        xor     cl,cl                   ;initialize loop count

absolute_loop:
        mov     dx,VGA_BASE + GRAF_ADDR
        out     dx,ax                   ;Set bitmask for altered bit

        bt      cl,0
        jc      @F

        movzx   edx,byte ptr [esi]      ;grab color for this and next pels
        inc     esi

        mov     iPels,edx               ;save for next pel
        shr     dl,4
        jmp short   ready_to_draw
@@:
        mov     edx,iPels               ;second pel
        and     dl,0Fh                  ;mask out the second pel

ready_to_draw:
        mov     edx,[ebx][edx*4]        ;look up for VGA color
        xchg    [edi],dl                ;write to destination

        ror     ah,1                    ;rotate bit mask for next pel
        cmp     ch,ah                   ;cmp bitmask with 01000001b
        adc     edi,0                   ;advance edi if bitmask is 10000000b

        inc     cl
        cmp     cl,nPels
        jnz short absolute_loop

        mov     eax,cPostSrcAdv

rle4_absolute_advance_src:
        shr     eax,1                   ;2 pels for one byte
        add     esi,eax                 ;advance src ptr for clipped out pels
        bt      esi,0                   ;add 1 if not word aligned
        adc     esi,0
        jmp     rle4_loop


rle4_end_of_line_or_bitmap:
        or      ah,ah
        jnz short rle4_end_of_bitmap

rle4_end_of_line:
        RleEOL  rle4_loop

rle4_done:
        RleExit

        RleBankBottom   rle4_bank_loop,rle4_exit ;see if there are more banks
                                                 ; to do
        align   4
rle4_end_of_bitmap:
        RleExit
rle4_exit:
        cRet    vRle4ToVga

endProc vRle4ToVga

;--------------------------Private-Routine------------------------------;
; comp_byte_interval
;
;   An interval will be computed for byte boundaries.
;
;   A first mask and a last mask will be calculated, and possibly
;   combined into the inner loop count.  If no first byte exists,
;   the start address will be incremented to adjust for it.
;
; Entry:
;       EBX = right coordinate (exclusive)
;       ECX = left coordinate  (inclusive)
; Returns:
;       EDI = offset to first byte to be altered in the scan
;       ECX = inner loop count
;       AL  = first byte mask (possibly 0)
;       AH  = last  byte mask (possibly 0)
; Error Returns:
;       None
; Registers Preserved:
;       ES,BP
; Registers Destroyed:
;       AX,BX,CX,DI,FLAGS
; Calls:
;       None
;
;-----------------------------------------------------------------------;

comp_masks      proc

        sub     ebx,ecx                 ;Compute extent of interval
        dec     ebx                     ;Make interval inclusive
        mov     edi,ecx                 ;Don't destroy starting X
        shr     edi,3                   ;/8 for byte address

        and     ecx,00000111b           ;Compute bit index for left side
        mov     al,0FFh                 ;Compute left side altered bits mask
        shr     al,cl                   ;AL = left side altered bytes mask

        add     ebx,ecx                 ;Compute bit index for right side
        mov     ecx,ebx                 ;(save for inner loop count)
        and     ecx,00000111b
        mov     ah,80h
        sar     ah,cl                   ;AH = right side altered bits mask

        shr     ebx,3                   ;Compute inner byte count
        jnz     short comp_byte_dont_combine ;loop count + 1 > 0, check it out

; Only one byte will be affected.  Combine first/last masks, set loop count = 0

        and     al,ah                   ;Will use first byte mask only
        xor     ah,ah                   ;Want last byte mask to be 0
        inc     ebx                     ;Fall through to set 0

comp_byte_dont_combine:
        dec     ebx                     ;Dec inner loop count (might become 0)

; If all pixels in the first byte are altered, combine the first byte into the
; inner loop and clear the first byte mask.  Ditto for the last byte mask.

        mov     ecx,0FFFFFFFFh
        cmp     al,cl                   ;Set 'C' if not all pixels 1
        sbb     ebx,ecx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     al,cl                   ;Set 'C' if not all pixels 1
        sbb     al,cl                   ;If no 'C', sub -1 (add 1), else sub 0

        cmp     ah,cl                   ;Set 'C' if not all pixels 1
        sbb     ebx,ecx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     ah,cl                   ;Set 'C' if not all pixels 1
        sbb     ah,cl                   ;If no 'C', sub -1 (add 1), else sub 0

        mov     ecx,ebx                 ;Return inner loop count in ECX

        ret

comp_masks endp

        end


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.