;*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     55,132
        TITLE    Run Length Encoded Bitmap
        SUBTITLE Header

;/*****************************************************************************
;*
;* SOURCE FILE NAME = RLEBM.ASM
;*
;* DESCRIPTIVE NAME = Run Length Encoded Bitmap functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/26/91
;*
;* DESCRIPTION
;*
;*    Draw RLE compressed bitmap at level of device driver.
;*
;*                RUN LENGTH ENCODED (RLE) BITMAPS
;*                --------------------------------
;*
;*    A RLE bitmap consists of two parts - an information header block and a
;*    coded buffer which we will refer to as the RLE bitmap.
;*
;*    Unlike normal bitmaps the RLE bitmap has the encoding of the information
;*    in a bitmap.  The incoding consists of a series of records of variable
;*    lengths, with the first byte of every record designating the type of the
;*    record.
;*
;*    The RLEs can be recorded in 8 bit mode or in 4 bit mode.  In 8 bit mode,
;*    all indices are byte valued, whereas in 4 bit mode the indices are
;*    specified in 4 bits and a byte will hold 2 of these indices.
;*
;*    The various types of records are classified below:
;*
;*  Encoding of a Runlength:
;*  ----------------------------
;*  FIRSTBYTE:  COUNT which is >= 1.
;*  SECONDBYTE: INDEX.
;*
;*    (8 BIT FORMAT)
;*      This is just a 2 BYTE record and encodes COUNT number of pels in the
;*      bitmap having the same color index. All indexes in the RLE records are
;*      with respect to the color table in the info header.
;*
;*    (4 BIT FORMAT)
;*      The second BYTE contains 2 color indices in 4 bits each and the first
;*      byte spcifies the number of pels of the alternating seq.  The color
;*      for the pels are obtained by alternately choosing the high and the low
;*      nibble, till COUNT number of pels are done.
;*
;*  Unencoded run:
;*  ------------------
;*  FIRSTBYTE: = 0.
;*  SECONDBYTE: COUNT >= 3. Followed by,
;*
;*    (8 BIT FORMAT)
;*      a string of BYTEs specifying the color indices, this string must be
;*      even, and be padded by a zero if the COUNT is ODD.
;*
;*    (4 BIT FORMAT)
;*      a string of bytes, each byte providing two 4 bit indices. The string
;*      must be even. There may be a filler byte and there maybe a byte with
;*      an index in just the left nibble.
;*
;*  Delta:
;*  ----------
;*  FIRSTBYTE:  = 0
;*  SECONDBYTE: = 2
;*  THIRDBYTE:  = DELTA_X (unsigned), >= 0
;*  FOURTHBYTE: = DELTA_Y (unsigned), >= 0, but not both 0
;*
;*    This is relative-jump record and implies that the decoding of the next
;*    RLE record is to start at (DELTA_X,DELTA_Y) wrt to the current position
;*    in the bitmap.
;*
;*  EOL (end-of-line):
;*  FIRSTBYTE:  = 0
;*  SECONDBYTE: = 0
;*
;*    Signifies the end of the current line in the bitmap. The decoding of the
;*    next record is to be done at the start of the next line.
;*
;*  EORLE (end-of-RLE):
;*  FIRSTBYTE:  = 0
;*  SECONDBYTE: = 1
;*
;*    Signifies the end of the encoding.
;*
;*
;* FUNCTIONS    Name
;*              ReadRLE
;*              SetGetByteMask
;*              DevicePartialSetPels
;*              DeviceFullSetPels
;*              DecideStrategy4Bit
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/26/91                     Written by Kenton E. Zahrt
;*   07/23/92              DCR37  JMW  Modified                                         *
;*
;*****************************************************************************/



        .386P
        .MODEL FLAT,SYSCALL

;/*
;** Included files
;*/

INCL_DDIBITMAPFILE EQU 1
INCL_GPIBITMAPS    EQU 1
INCL_GPIPRIMITIVES EQU 1
INCL_NOBASEAPI     EQU 1
INCL_SAADEFS       EQU 1
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC

DINCL_BB_ROPS      EQU 1
DINCL_BITMAP       EQU 1
DINCL_ENABLE       EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC
        INCLUDE EGAFAM.INC
        INCLUDE ASSERT.MAC


;/*
;** Equates
;*/

RLE_CLIPPED EQU 00000001b       ; Clipping is required

;/*
;** Macros
;*/

;/*
;** The following macro provides a common frame definition for all functions
;** that use it.  The primary purpose is to allow a subroutine to be called and
;** use the parent's call frame (including local variables).  This can be
;** accomplished by disabling prologues and epilogues for the child function and
;** using the StdProc macro to define the PROC.  The child function now
;** understands the identifiers in the frame as offsets from EBP, and since EBP
;** is not updated by the prologue, it is a valid reference to the ancestor's
;** frame.
;*/

StdProc MACRO   Name,Visibility

Name PROC SYSCALL Visibility uses EBX EDI ESI,
 pDestDDC    :DWORD, lDestX      :DWORD,
 lDestY      :DWORD, pRLEInfo    :DWORD,
 lLeftClipX  :DWORD, lBottomClipY:DWORD,
 lExtentX    :DWORD, lExtentY    :DWORD,
 pRLEBits    :DWORD, pColorTable :DWORD
 LOCAL  cDestScanCt             :DWORD  ; Total bytes in a scan
 LOCAL  cEncodeShft             :DWORD
 LOCAL  lX                      :DWORD  ; Current lX on display
                                        ; surface
 LOCAL  lY                      :DWORD  ; Current lY on display
                                                ; surface
 LOCAL  pfnDecideStrat          :DWORD  ; Decides strategy to adopt
 LOCAL  pfnGetAbsIndx           :DWORD  ; Addr of func to get next
                                                ; abs mode index
 LOCAL  pfnUpdateSrcPtr         :DWORD  ; Addr of func to update src
                                                ; pointer
 LOCAL  selScreen               :DWORD  ; Pointer to start of surface
 LOCAL  usNibbleToggle          :DWORD  ; Decides which nibble to use
 LOCAL  lRightClipX             :DWORD  ; Right of clip rectangle
 LOCAL  lTopClipY               :DWORD  ; Bottom of the clip rect
 LOCAL  fbSurfaceFlags          :BYTE   ; Defines the following flags
 LOCAL  fOddPels                :BYTE   ; Flag for odd number of pels
 LOCAL  bkmix                   :BYTE   ; Background mix
 LOCAL  bkclr                   :BYTE   ; Background color
 LOCAL  pfnSet4BPPOnepelSegment :DWORD  ; Addr of func to set 4BPP
 LOCAL  pfnSetOnepelSegment     :DWORD  ; Addr of func to set 8BPP
 LOCAL  pfnSetMultipelSegment   :DWORD  ; Addr of func to set multiple pels

ENDM    ; StdProc

;/*
;** Private functions
;*/

        .CODE

        SUBTITLE ReadRLE
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = ReadRLE
;*
;* DESCRIPTION   = Reads a BYTE from a encoded RLE buffer.
;*
;*                 Registers modified:
;*                   EAX ESI
;*
;* INPUT         = ESI --> RLE buffer
;*
;* OUTPUT        = AL  = Byte from buffer
;*                 ESI = Incremented
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ReadRLE PROC SYSCALL PRIVATE

        lodsb
        ret

ReadRLE ENDP

        SUBTITLE SetGetSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetGetSegment
;*
;* DESCRIPTION   =
;*
;*     Gets a portion of the current segment from (lX,lY) to (lX+AX,lY) which
;*     fits within the clip rectangle.
;*
;*     We will divide the region surrounding the clip rectangle into 4 areas as
;*     shown below.  The segment is totally clipped if it lies totally in any
;*     of the four regions.  If it is not totally clipped, there can be 4 ways
;*     that the segment may reside.  These are all shown below.
;*
;*                                       region-1
;*                 <---------------------------------------------------->
;*                       |                                      |
;*                       |                                      |
;*                       |                                      |
;*          region-4     |          The Clip Rectangle          |  region-2
;*                       |                                      |
;*                 type_1|              type_2            type_3|
;*                 ------|------      ----------          ------|-----
;*                 ------|--------------------------------------|----- type_4
;*                 <---------------------------------------------------->
;*                                       region-3
;*
;*
;*
;*
;*
;* INPUT         = (lX,lY)           - Start of segment for current RLE record
;*                 (ClipLft,ClipTop) - Top left of the clip rectangle
;*                 (ClipRgt,ClipBot) - Bottom right of the clip rectangle
;*                 EAX               - Number of pels in the segment
;*
;* OUTPUT        = ECX - No of pels within clip rectangle, 0 => total clip
;*                       (if CX=0, rest is not valid)
;*                 EAX - No of pels clipped on left
;*                 EBX - No of pels clipped on right
;*                 EDI - Absisca of first visible pel in the segment
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc SetGetSegment,PUBLIC

        DebugMsg <Entering RLEBM.SetGetSegment,Private,KEZ>

        test    fbSurfaceFlags,RLE_CLIPPED
        jz      SetGetSegment_not_clipped
        mov     ebx,lX                          ; Get left abscissa of segment
        mov     edi,lY                          ; Get ordinate
        xor     ecx,ecx                         ; Assume total clip

;/*
;** If lY is > ClipTop (region-3) or < ClipBot (region_1) it is totall clipped.
;*/

        cmp     edi,lBottomClipY
        jb      SetGetSegment_end               ; Segment is totaly clipped
        cmp     edi,lTopClipY
        jae     SetGetSegment_end               ; Segment is totaly clipped

;/*
;** lY ordinate is OK, but we may still be in region-2 or -4.
;*/

        cmp     ebx,lRightClipX         ; Are we in region-2
        jae     SetGetSegment_end       ;  Y - So nothing is visible
        push    eax                     ; Save extent
        add     eax,ebx                 ; Ax has coord just past rt edge of
                                        ; seg
        cmp     eax,lLeftClipX          ; Are we in region-4
        pop     eax                     ; Get back extent in EAX
        jbe     SetGetSegment_end       ; Another total clip case

;/*
;** At least a part of the segment is visible. Find out the type of clip.
;*/

        mov     ecx,eax                 ; Assume all is visible
        xor     eax,eax                 ; and nothing cliped on left
        cmp     ebx,lLeftClipX          ; Do we start on the left edge?
        je      Set_start_on_lft_edge   ;  Y
        jg      Set_clip_type_2_or_3    ;  Can't be clip type 1 or 4

;/*
;** We have clip type 1 or 4, so a portion is clipped off the left end.
;*/

        sub     ebx,lLeftClipX
        neg     ebx                     ; No. of pels clipped from left end
        sub     ecx,ebx                 ; EBX less pixels to draw
        mov     eax,ebx                 ; Remember left cliped pixels

Set_start_on_lft_edge:

        mov     edi,lLeftClipX          ; Start on left edge
        mov     ebx,lExtentX            ; Get extent not exceeding clip rect
        jmp     SetGetSegment_right_clip

Set_clip_type_2_or_3:

        mov     edi,ebx                 ; Start abscissa of visible segment
        sub     ebx,lRightClipX         ; EBX has left X of segment
        neg     ebx

;/*
;**   ecx is wanted extent
;**   ebx is max alowed extent
;*/

SetGetSegment_right_clip:

        cmp     ecx,ebx                         ; Are we clipped on the right?
        ja      SetGetSegment_right_clipped
        xor     ebx,ebx                         ;  N - Set rt. clipped to zero
        jmp     SetGetSegment_end

SetGetSegment_right_clipped:

        sub     ecx,ebx                 ; We are right cliped,set...
        xchg    ecx,ebx

;/*
;**   eax is amount left clipped
;**   ecx is clipped extent
;**   ebx is amount right clipped
;*/

SetGetSegment_end:

        jmp     SetGetSegment_Exit

SetGetSegment_not_clipped:

        mov     edi,lX
        mov     ecx,eax
        xor     eax,eax
        xor     ebx,ebx

SetGetSegment_Exit:

        DebugMsg <Leaving SetGetSegment>

        ret

SetGetSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE SetStartOffset
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetStartOffset
;*
;* DESCRIPTION   =  Find the offset in surfaces that will not exceed 64k in size.
;*
;* INPUT         = (EDI,lY) - Start coordinate on display surface.
;* OUTPUT        = EDI --> Start byte on display surface.
;*                 DL   -  Number of bits in 1st byte to left of start bit.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc SetStartOffset,PUBLIC

        mov     eax,lDestY
        sub     eax,lY
        add     eax,lBottomClipY        ;Current scan
        mul     cDestScanCt             ;Number of bytes in a scan
        sub     edi,lLeftClipX
        add     edi,lDestX              ;Get the X origin
        mov     edx,edi                 ;Get start X
        add     edi,eax                 ;edi has correct offset
        push    edx
        push    edi
        shr     edi,16                  ;Move bank number to lower word
        mov     edx,edi                 ;dl now has bank number
        call    set_bank_select         ;Set current bank
        pop     edi
        pop     edx
        movzx   edi,di                  ;Remove bank number
        add     edi,selScreen           ;Add destination address
        ret

SetStartOffset ENDP


        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE SetMultipelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetMultipelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are of different colors.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - Number of pels in the segment.
;*                 ESI    --> Index for the first pel in the segment.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc SetMultipelSegment,PUBLIC

        DebugMsg <Entering RLEBM.SetMultipelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table

Set_multipel_loop:

        call    pfnGetAbsIndx           ; Get next pel index
        xlat    [ebx]                   ; Get the color value for the index
        stosb                           ; Set the pel

        loop    Set_multipel_loop

        DebugMsg <Leaving SetMultipelSegment>

        ret

SetMultipelSegment endp


        SUBTITLE SetOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = SetOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are all of the same color.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment
;*                 ESI      - Pointer to the index for the pel color
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc SetOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.SetOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        xchg    ecx,cEncodeShft
        mov     al,[esi]                ; Fetch the encode byte
        shr     al,cl                   ; If 4bpp,left nibble of interest
        xchg    ecx,cEncodeShft
        xlat    [ebx]                   ; Get the color value for the index
        rep     stosb                   ; Do all bytes

        DebugMsg <Leaving SetOnepelSegment>

        ret

SetOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE Set4BPPOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = Set4BPPOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels in
;*                 the segment are of alternating colors.  This is used for
;*                 playing back encoded pels in 4 bit RLE.  We basically will
;*                 make two passes, the first pass will set all the pels of
;*                 the first color and the next will set all the pels of the
;*                 other color.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment.
;*                 ESI      - Pointer to the index for the 2 pel colors.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc Set4BPPOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.Set4BPPOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        shr     ecx,1                   ; Two pels per loop
        cmp     ecx,0                   ; If only one pel
        jz      BPP_LastPel             ;  do only that pel
        mov     fOddPels,0              ; Initialize flag as even pels
        test    ecx,1                   ; If odd number of pels
        jnz     Initialize_loop         ;  must skip last pel
        mov     fOddPels,1              ; Flag as odd number of pels
Initialize_loop:
        mov     al,[esi]
        mov     ah,al                   ; First nibble
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        and     ah,0fh                  ; Second nibble
        xchg    al,ah                   ; 
        xlat    [ebx]                   ; Get the color value for the index
Set_4BPP_onepel_loop:
        xchg    al,ah                   ; First nibble
        stosb
        xchg    al,ah                   ; Second nibble
        stosb
        loop    Set_4BPP_onepel_loop

        cmp     fOddPels,0              ; If even number of pels
        jz      BPP_Done                ;  did them all
BPP_LastPel:
        mov     al,[esi]                ; Do last odd pel
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        stosb
BPP_Done:

        DebugMsg <Leaving Set4BPPOnepelSegment>

        ret

Set4BPPOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE d_SetMultipelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = d_SetMultipelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are of different colors with background
;*                 mix BM_DESTTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - Number of pels in the segment.
;*                 ESI    --> Index for the first pel in the segment.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc d_SetMultipelSegment,PUBLIC

        DebugMsg <Entering RLEBM.d_SetMultipelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        mov     ah,bkclr
d_Set_multipel_loop:
        call    pfnGetAbsIndx           ; Get next pel index
        cmp     ah,byte ptr[edi]        ; Color == background color ?
        jne     d_color_notfound        ; If not, point to next byte
        xlat    [ebx]                   ; Get the color value for the index
        stosb                           ; If so, set the pel
        loop    d_Set_multipel_loop     ; Get the next byte
        jmp     @f
d_color_notfound:
        inc     edi                     ; Trans color notfound, point to next byte
        loop    d_Set_multipel_loop     ; Get the next byte
@@:

        DebugMsg <Leaving d_SetMultipelSegment>

        ret

d_SetMultipelSegment endp


        SUBTITLE d_SetOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = d_SetOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are all of the same color with background
;*                 mix BM_DESTTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment
;*                 ESI      - Pointer to the index for the pel color
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc d_SetOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.d_SetOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        xchg    ecx,cEncodeShft
        mov     al,[esi]                ; Fetch the encode byte
        shr     al,cl                   ; If 4bpp,left nibble of interest
        xchg    ecx,cEncodeShft
        xlat    [ebx]                   ; Get the color value for the index
        mov     ah,bkclr
d_Set_onepel_loop:
        cmp     ah,byte ptr[edi]        ; Color == background color ?
        jne     d_color_not_found1      ; If not, exit
        stosb                           ; If so, set the pel
        loop    d_Set_onepel_loop       ; Get the next byte
        jmp     @f
d_color_not_found1:
        inc     edi                     ; Trans color not found, point to next byte
                                        ;  of different color
        loop    d_Set_onepel_loop
@@:

        DebugMsg <Leaving d_SetOnepelSegment>

        ret

d_SetOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE d_Set4BPPOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = d_Set4BPPOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels in
;*                 the segment are of alternating colors.  This is used for
;*                 playing back encoded pels in 4 bit RLE with background
;*                 mix BM_DESTTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment.
;*                 ESI      - Pointer to the index for the 2 pel colors.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc d_Set4BPPOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.d_Set4BPPOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        push    edx
        mov     ebx,pColorTable         ; Address of the translation table
        shr     ecx,1                   ; Two pels per loop
        cmp     ecx,0                   ; If only one pel
        jz      d_BPP_LastPel           ;  do only that pel
        mov     fOddPels,0              ; Initialize flag as even pels
        test    ecx,1                   ; If odd number of pels
        jnz     d_Initialize_loop       ;  must skip last pel
        mov     fOddPels,1              ; Flag as odd number of pels
d_Initialize_loop:
        mov     al,[esi]
        mov     ah,al                   ; First nibble
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        and     ah,0fh                  ; Second nibble
        xchg    al,ah                   ; 
        xlat    [ebx]                   ; Get the color value for the index
d_Set_4BPP_onepel_loop:
        xchg    al,ah                   ;First nibble
        mov     dl,byte ptr[edi]
        cmp     dl,bkclr
        jne     d_color_not_found2
        stosb
        jmp     @f
d_color_not_found2:
        inc     edi                     ; Trans color notfound, point to next byte
@@:
        xchg    al,ah                   ; Second nibble
        mov     dl,byte ptr[edi]
        cmp     dl,bkclr
        jne     d_color_not_found3
        stosb
        loop    d_Set_4BPP_onepel_loop
        jmp     @f
d_color_not_found3:
        inc     edi                     ; Trans color notfound, point to next byte
        loop    d_Set_4BPP_onepel_loop
@@:
        cmp     fOddPels,0              ; If even number of pels
        jz      d_BPP_Done              ;  did them all
d_BPP_LastPel:
        mov     dl,byte ptr[edi]
        cmp     dl,bkclr
        jne     d_color_not_found4
        mov     al,[esi]                ; Do last odd pel
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        stosb
        jmp     d_BPP_Done
d_color_not_found4:
        inc     edi                     ; Trans color notfound, point to next byte
d_BPP_Done:
        pop     edx

        DebugMsg <Leaving d_Set4BPPOnepelSegment>

        ret

d_Set4BPPOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE s_SetMultipelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = s_SetMultipelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are of different colors with background
;*                 mix BM_SRCTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - Number of pels in the segment.
;*                 ESI    --> Index for the first pel in the segment.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc s_SetMultipelSegment,PUBLIC

        DebugMsg <Entering RLEBM.s_SetMultipelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
s_Set_multipel_loop:
        call    pfnGetAbsIndx           ; Get next pel index
        xlat    [ebx]                   ; Get the color value for the index
        cmp     al,bkclr                ; Color == background color ?
        je      s_color_found           ; If so, point to next byte
        stosb                           ; If not, copy to screen
        loop    s_Set_multipel_loop     ; Get the next byte
        jmp     @f
s_color_found:
        inc     edi                     ; Trans color found, point to next byte
        loop    s_Set_multipel_loop     ; Get the next byte
@@:

        DebugMsg <Leaving s_SetMultipelSegment>

        ret

s_SetMultipelSegment endp


        SUBTITLE s_SetOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = s_SetOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels
;*                 in the segment are all of the same color with background
;*                 mix BM_SRCTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment
;*                 ESI      - Pointer to the index for the pel color
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc s_SetOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.s_SetOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        xchg    ecx,cEncodeShft
        mov     al,[esi]                ; Fetch the encode byte
        shr     al,cl                   ; If 4bpp,left nibble of interest
        xchg    ecx,cEncodeShft
        xlat    [ebx]                   ; Get the color value for the index
        cmp     al,bkclr                ; Color == background color ?
        je      s_color_found1          ; If so, exit
        rep     stosb                   ; Do all bytes
        jmp     @f
s_color_found1:
        add     edi,ecx                 ; Trans color found, point to next byte
@@:                                     ;  of different color

        DebugMsg <Leaving s_SetOnepelSegment>

        ret

s_SetOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE s_Set4BPPOnepelSegment
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = s_Set4BPPOnepelSegment
;*
;* DESCRIPTION   = Draws a segment onto the display surface, where the pels in
;*                 the segment are of alternating colors.  This is used for
;*                 playing back encoded pels in 4 bit RLE with background
;*                 mix BM_SRCTRANSPARENT.
;*
;* INPUT         = (EDI,lY) - Start coordinate of the segment.
;*                 ECX      - No pels in the segment.
;*                 ESI      - Pointer to the index for the 2 pel colors.
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc s_Set4BPPOnepelSegment,PUBLIC

        DebugMsg <Entering RLEBM.s_Set4BPPOnepelSegment,Private,KEZ>

        call    SetStartOffset

;/*
;** EDI points to byte on destination surface.
;*/

        mov     ebx,pColorTable         ; Address of the translation table
        shr     ecx,1                   ; Two pels per loop
        cmp     ecx,0                   ; If only one pel
        jz      s_BPP_LastPel           ;  do only that pel
        mov     fOddPels,0              ; Initialize flag as even pels
        test    ecx,1                   ; If odd number of pels
        jnz     s_Initialize_loop       ;  must skip last pel
        mov     fOddPels,1              ; Flag as odd number of pels
s_Initialize_loop:
        mov     al,[esi]
        mov     ah,al                   ; First nibble
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        and     ah,0fh                  ; Second nibble
        xchg    al,ah                   ; 
        xlat    [ebx]                   ; Get the color value for the index
s_Set_4BPP_onepel_loop:
        xchg    al,ah
        cmp     al,bkclr                ; Color == background color ?
        je      s_color_found2          ; If so, point to next byte
        stosb                           ; If not, copy to screen
        jmp     @f
s_color_found2:
        inc     edi                     ; Trans color found, point to next byte
@@:
        xchg    al,ah
        cmp     al,bkclr                ; Color == background color ?
        je      s_color_found3          ; If so, point to next byte
        stosb                           ; If not, copy to screen
        loop    s_Set_4BPP_onepel_loop
        jmp     @f
s_color_found3:
        inc     edi                     ; Trans color found, point to next byte
        loop    s_Set_4BPP_onepel_loop
@@:
        cmp     fOddPels,0              ; If even number of pels
        jz      s_BPP_Done              ;  did them all
s_BPP_LastPel:
        mov     al,[esi]                ; Do last odd pel
        shr     al,4
        xlat    [ebx]                   ; Get the color value for the index
        cmp     al,bkclr                ; Color == background color ?
        je      s_color_found4          ; If so, point to next byte
        stosb                           ; If not, copy to screen
        jmp     s_BPP_Done
s_color_found4:
        inc     edi                     ; Trans color found, point to next byte
s_BPP_Done:

        DebugMsg <Leaving s_Set4BPPOnepelSegment>

        ret

s_Set4BPPOnepelSegment ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

;/*
;** Public functions
;*/

        SUBTITLE RLEDrawBits
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = RLEDrawBits
;*
;* DESCRIPTION   = Display Run-Length-Encoded bitmaps.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


StdProc RLEDrawBits,PUBLIC

        DebugMsg <Entering RLEBM.RLEDrawBits,Public,KEZ>

        cld

;/*
;** Set up the address to the first byte of the screen, and adjust lY origin.
;*/

RDB_Dst_info:

        mov     esi,pDestDDC            ; esi => the dest. DDC

;/*
;** Check for background mixes of BM_SRCTRANSPARENT or BM_DESTTRANSPARENT.
;** BM_SRCTRANSPARENT will result in pels from the source bitmap matching
;** the presentation space background color NOT to be copied to the
;** destination bitmap. (OVERLAY)
;** BM_DESTTRANSPARENT will result in pels from the source bitmap ONLY
;** being copied to the destination pels that match the presentation space
;** background color. (UNDERLAY)
;** If either is requested, save the background color and background mix.
;*/

        ASSUME  esi:PDDC
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_DESTTRANSPARENT ;Destination transparent ?
        jne     @f                                       ;If not, check for SRCTRANSPARENT
        mov     bkmix,BM_DESTTRANSPARENT
        mov     eax,[esi].ddc_pa.pa_ba.ba_clrBack        ;Save background color
        mov     bkclr,al
        mov     pfnSet4BPPOnepelSegment,OFFSET d_Set4BPPOnepelSegment
        mov     pfnSetOnepelSegment,OFFSET d_SetOnepelSegment
        mov     pfnSetMultipelSegment,OFFSET d_SetMultipelSegment
        jmp     bkmix_known
@@:
        cmp     [esi].ddc_pa.pa_ba.ba_bkmix,BM_SRCTRANSPARENT  ;Source transparent ?
        jne     @f                                       ;If not, use default
        mov     bkmix,BM_SRCTRANSPARENT
        mov     eax,[esi].ddc_pa.pa_ba.ba_clrBack        ;Save background color
        mov     bkclr,al
        mov     pfnSet4BPPOnepelSegment,OFFSET s_Set4BPPOnepelSegment
        mov     pfnSetOnepelSegment,OFFSET s_SetOnepelSegment
        mov     pfnSetMultipelSegment,OFFSET s_SetMultipelSegment
        jmp     bkmix_known
@@:
        mov     pfnSet4BPPOnepelSegment,OFFSET Set4BPPOnepelSegment
        mov     pfnSetOnepelSegment,OFFSET SetOnepelSegment
        mov     pfnSetMultipelSegment,OFFSET SetMultipelSegment
        mov     bkmix,0
bkmix_known:
        ASSUME  esi:nothing


        mov     esi,[ESI].DDC.ddc_npsd  ; esi => the dest. surface
        mov     eax,[ESI].SURFACE.sd_pBits      ; The screen address
        mov     selScreen,eax
        mov     cDestScanCt,SCREEN_DSCAN

;/*
;** Calculate the source rectangle.
;*/

RDB_Src_rect:

        xor     eax,eax                 ; The RLE starts from origin(0,0)
        mov     lX,eax                  ; Start lX coordinate
        mov     lY,eax                  ; Start lY coordinate
        mov     eax,lLeftClipX          ; The left edge
        add     eax,lExtentX
        mov     lRightClipX,eax         ; The right edge
        mov     eax,lBottomClipY        ; The top edge
        add     eax,lExtentY
        mov     lTopClipY,eax           ; The Bottom edge

;/*
;** Special care must be taken if the width of the rectangle to draw does not
;** cover the full scanwidth. We treat that case as a clipped rectangle.
;*/

RDB_Clip_test:

        mov     esi,pRLEInfo            ; esi points to RLE info block
        mov     eax,lExtentX
        cmp     eax,[ESI].BITMAPINFOHEADER2.bmp2_cx     ; If the drawing width
                                                        ; is not equal to the
        setne   fbSurfaceFlags                          ; bitmap width,
                                                        ; indicate clipped
                                                        ; rect
        .ERRNZ  RLE_CLIPPED-00000001b

        mov     eax,lExtentY
        cmp     eax,[ESI].BITMAPINFOHEADER2.bmp2_cy     ; If the drawing
        setne   al                                      ; height is not equal
        or      fbSurfaceFlags,al                       ; to the bitmap
                                                        ; height, indicate
                                                        ; clipped rect

;/*
;** Depending on 4 bit or 8 bit encoding set up function address variables.
;*/

RDB_4bpp_addr:

        cmp     [ESI].BITMAPINFOHEADER2.bmp2_ulCompression,BCA_RLE8
        je      RDB_8bpp_addr

;/*
;** Set up function addresses for 4 bit encoding.
;*/

        mov     eax,4                   ; We need only the encode nibble
        mov     ebx,DecideStrategy4Bit
        mov     ecx,UpdateSourcePointer4Bit
        mov     edx,GetNextAbsoluteIndex4Bit
        jmp     RDB_Have_addr

;/*
;** Set up function addresses for 8 bit encoding.
;*/

RDB_8bpp_addr:

        xor     eax,eax                 ; We need the full encode byte
        mov     ebx,SameColorStrategy
        mov     ecx,Update_src_ptr_8_bit
        mov     edx,ReadRLE

RDB_Have_addr:

        mov     cEncodeShft,eax
        mov     pfnDecideStrat,ebx
        mov     pfnUpdateSrcPtr,ecx
        mov     pfnGetAbsIndx,edx


;/*
;** Cursor Exclusion for a device destination.
;*/

RDB_Cursor_exclude:

        mov     esi,lExtentX
        mov     edi,lExtentY
        dec     esi                     ; Make extents inclusive of last point
        dec     edi
        mov     ecx,lDestX              ; Set left
        mov     edx,lDestY              ; Set top
        add     esi,ecx                 ; Set right
        add     edi,edx                 ; Set bottom

        INVOKE  far_exclude             ; Exclude the area from the screen

;/*
;** The lY orientation of an RLE is inverse of the         convention.This thus
;** means that we start setting bits to/geting bits from the display surface
;** at (lDestX,lDestY+lExtentY-1). Set up the start lX and lY coordinates.                   |
;*/

RDB_Adjust_lDestY:

        mov     eax,lDestY              ; Get the lY origin (top scan)
        add     eax,lExtentY            ; Move it to the bottom of scan
        dec     eax
        mov     lDestY,eax              ; Adjusted lY origin

;/*
;** Set up the EGA registers for write mode 2.
;*/

RDB_Init_board:

        mov     esi,pRLEBits            ; esi points to rle buffer

;/*
;** The current position in the source is at (lX,lY).  The clipping rectangle is
;** from (lLeftClipX,lBottomClipY) to (lRightClipX,lTopClipY).
;*/

RDB_Set_decode_RLE:

        xor     eax,eax                 ; Count is 1 byte
        mov     usNibbleToggle,eax      ; Used for 4 bit RLEs
        lodsb                           ; Get the next byte
        or      al,al                   ; Is it 0
        jnz     RDB_Set_encoded_run     ; The next byte has the color index.

;/*
;** Possibilities are: we may have,
;**       . End of Line            -  If next BYTE is 0,
;**       . End of RLE             -  If next BYTE is 1,
;**       . Delta                  -  If next BYTE is 2
;**       . Unencoded run          -  If next BYTE is 3 or more
;*/


        lodsb                           ; Get the next byte
        cmp     al,3                    ; Absolute mode ?
        jae     RDB_Set_absolute_mode   ; Absolute mode of encoding
        cmp     al,2                    ; Delta or segment cross
        je      RDB_Set_delta           ; Yes
        or      al,al                   ; End of line?
        jz      RDB_Set_EOL             ; Yes
        jmp     RDB_Set_EORLE           ; End of encoding

;/*
;** We have an unencoded run, COUNT INDEX1 INDEX2 ...,with no. of indexes in
;** the run being in EAX.
;*/

RDB_Set_absolute_mode:

        push    eax                             ; Save the count of RLE
        test    fbSurfaceFlags,RLE_CLIPPED
        jz      RDB_Set_multipel_not_cliped

;/*
;** Calculate the portion of the above segment that is within the clipping
;** rect.
;*/

        call    SetGetSegment                   ; Set up params for multipel
                                                ; segment

;/*
;**   eax is pixels cliped on left
;**   ecx is pixels visible
;**   ebx is pixels cliped on right
;*/

        call    pfnUpdateSrcPtr                 ; Advance over left clipped
                                                ; pels
        jecxz   RDB_Set_multipel_update_X_Y     ; Segment is clipped

;/*
;** At least a part of the segment is visible. (DI,lY) has the start
;** coordinate, ecx has the extent and esi points to the index of the first
;** pel in the visible part.
;*/

        push    ebx                             ; Save right clipped count
        call    pfnSetMultipelSegment           ; Draws the segment, pels of
                                                ; diff color
        pop     eax                             ; Restore right clip count and
        call    pfnUpdateSrcPtr                 ; advance over clipped pels
        jmp     RDB_Set_multipel_update_X_Y

;/*
;** All the pels for this record will be drawn to the screen.
;*/

RDB_Set_multipel_not_cliped:

        mov     edi,lX
        mov     ecx,eax
        call    pfnSetMultipelSegment   ; Draws the segment, pels of diff
                                        ; color

;/*
;** Now update (lX,lY) to account for the coding in the present RLE record.
;*/

RDB_Set_multipel_update_X_Y:

        mov     eax,usNibbleToggle
        call    pfnUpdateSrcPtr
        pop     eax                     ; Get back count of indices in record
        add     lX,eax                  ; Update the abscissa.
        test    esi,1                   ; WORD align source pointer
        jz      RDB_Set_decode_RLE
        lodsb                           ; Get the next byte

@@:
        jmp     RDB_Set_decode_RLE      ; Continue with next record

;/*
;** The record is a COUNT INDEX type of record and all pels in the segment are
;** of the same color. If we are in 4 bit encoding mode, two things could
;** happen:
;**   . If the two nibbles are the same, we will treat this to be a truly
;**     encoded record just as we do in the case of 8 bit mode.
;**
;**   . If the two nibbels do not have the same value then we will do the
;**     decoding in two passes, the first one will set all the pels in the run
;**     to the first color and the next one will alternating pels to the
;**     second color.
;**
;** We call a function to decide on the display strategy. First, obtain the
;** start coordinate in the segment and extent wrt the clip rectangle.
;*/

RDB_Set_encoded_run:

        push    eax                             ; Save count
        call    SetGetSegment                   ; Get start (x,y) in segment
                                                ; and count
        jecxz   RDB_Set_onepel_update_X_Y       ; The whole segment is clipped
        call    pfnDecideStrat                  ; Decide how to treat 4 bit
                                                ; encoding
        jnc     RDB_Treat_as_encoded            ; Stretch of same color

;/*
;** We have a stretch of alternating colors.
;*/

        call    pfnSet4BPPOnepelSegment         ; Draw visible part of segment
        jmp     RDB_Set_onepel_update_X_Y

;/*
;** At least a part is visible.  (EAX,lY) has start coordinate, ECX has extent,
;** ESI points to the pel index to be used for each pel in the segment.
;*/

RDB_Treat_as_encoded:

        call    pfnSetOnepelSegment             ; Draw visible part of segment

;/*
;** Update (lX,lY) for start of next RLE record.
;*/

RDB_Set_onepel_update_X_Y:

        lodsb                                   ; Get the next byte
        pop     eax                             ; Get back count of pels in
                                                ; RLE record
        add     lX,eax                          ; Move lX, lY stays the same,
                                                ; esi is OK
        jmp     RDB_Set_decode_RLE              ; Decode next RLE record.

;/*
;** We have reached a delta record.
;*/

RDB_Set_delta:

        lodsb                                   ; Get the next byte
        xor     ah,ah
        mov     ebx,eax                         ; Save in ebx
        lodsb                                   ; Get the next byte

;/*
;** We have a DELTA encoded record, DELTA_X is in EBX and DELTA_Y in EAX.
;** Update the current position to be (X+DELTA_X,Y+DELTA_Y).
;*/

        add     lX,ebx                  ; Update lX
        add     eax,lY                  ; Update lY
        cmp     eax,lTopClipY           ; Do we pass the top edge?
        jae     RDB_Set_EORLE           ; Yes, we are done. go to reset HW
        mov     lY,eax                  ; Yes, no, actually update lY
        jmp     RDB_Set_decode_RLE      ; Decode next  record

;/*
;** we have an end-of-line record. The action is to update lY and have the lX
;** same as the left edge of the destination rectangle. Since we are traversing
;** the surface in the reverse direction, we will have to decrement Y.
;*/

RDB_Set_EOL:

        mov     lX,eax                  ; Reset the abscissa
        inc     lY                      ; Point to next scan
        mov     eax,lTopClipY
        cmp     lY,eax                  ; Do we pass the top edge?
        jb      RDB_Set_decode_RLE      ;  N - Next RLE

;/*
;** We are done with the blitting. Restore device programming if necessary.
;*/

RDB_Set_EORLE:

        INVOKE  far_unexclude                   ; Allow cursor to be drawn

rdb_exit:

        DebugMsg <Leaving RLEDrawBits>

        ret

RLEDrawBits ENDP


        SUBTITLE UpdateSourcePointer4Bit
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = UpdateSourcePointer4Bit
;*
;* DESCRIPTION   = The following two routines are for updating the source
;*                 pointer after doing an absolute run of pels.  The first
;*                 routine is for 8 bit encoding and the next is for 4 bit
;*                 encoding.
;*
;* INPUT         = ESI --> Start of last record.
;*                 EAX  =  Number of pels encoded in last record.
;*
;* OUTPUT        = ESI --> Start of next record.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc UpdateSourcePointer4Bit,PUBLIC

        add     eax,usNibbleToggle      ; Handle odd nibble dudes
        mov     usNibbleToggle,eax      ; Save low bit in usNibbleToggle
        and     usNibbleToggle,1
        shr     eax,1                   ; Convert nibble count to bytes

Update_src_ptr_8_bit::

        add     esi,eax                 ; Point to next RLE record
        ret

UpdateSourcePointer4Bit ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE GetNextAbsoluteIndex4Bit
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = GetNextAbsoluteIndex4Bit
;*
;* DESCRIPTION   = Routine for 4 bit encoding.  BitToggle if 0, return the
;*                 left nibble of the current byte, else return the right
;*                 nibble and bump the pointer.
;*
;*
;*
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

StdProc GetNextAbsoluteIndex4Bit,PUBLIC

        xor     usNibbleToggle,1        ; Update the toggle switch
        test    usNibbleToggle,1        ; Test state
        jnz     Left_nibble_4_bit       ; Was zero, so return left nibble

;/*
;** The state was 1, return the right nibble and bump the pointer.
;*/

        lodsb                           ; Get the next byte
        and     al,0fh                  ; Retain the left nibble.
        jmp     GNAI_Exit

;/*
;** The state was 0, retun the left nibble rotated into the right nibble.
;*/

Left_nibble_4_bit:

        mov     al,[esi]                ; Get the current byte
        shr     al,4                    ; Get the left nibble into the right

GNAI_Exit:

        ret

GetNextAbsoluteIndex4Bit ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        SUBTITLE DecideStrategy4Bit
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = DecideStrategy4Bit
;*
;* DESCRIPTION   = The following routine decides what strategy is to be
;*                 adopted for handling encoded run in 4 bit mode.  For
;*                 stretches of the same color we will reset the carry flag
;*                 and return, but for alternate color stretches, we will
;*                 set carry and return.  For 8 bit mode, the address of the
;*                 part that clears the carry should be saved in the calling
;*                 memory variable.
;*
;* INPUT         = ESI --> Encode records index byte.
;*                 EAX --- To be preserved.
;* OUTPUT        = CARRY -- Set if the run is of alternate colors.
;*                 CARRY -- Cleared if the run is of the same color
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

DecideStrategy4Bit PROC SYSCALL PUBLIC

        push    eax
        mov     al,[esi]                ; Get the index
        mov     ah,al                   ; Have a copy
        and     al,0fh                  ; Get the lower index
        shr     ah,4                    ; Have the shifted upper index
        cmp     al,ah                   ; Compare the two
        pop     eax
        je      SameColorStrategy       ; stretch is of same color
        stc                             ; Set carry flag, different color
        jmp     DS4B_Exit

SameColorStrategy::

        clc                             ; Reset carry

DS4B_Exit:

        ret

DecideStrategy4Bit ENDP

        END
