;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = RLEBM.ASM
;*
;* DESCRIPTIVE NAME = Run Length Encoded Bitmap functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/24/90
;*
;* 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    RLEDrawBits
;*              ReadRLE
;*              set_get_segment
;*              set_multipel_segment
;*              set_onepel_segment
;*              set_4bpp_onepel_segment
;*              dev_set_pels_partial
;*              dev_set_pels_full
;*              set_get_bit_mask
;*              set_get_byte_mask
;*              set_start_offset
;*              update_src_ptr_4_bit
;*              get_next_abs_index_4_bit
;*              decide_strategy_4_bit
;*
;* NOTES        
;*              
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*****************************************************************************/

        .286P

        .xlist
        include cmacros.inc
INCL_GPIBITMAPS         equ                      1       ; for bitmap info structure
INCL_GPILOGCOLORTABLE   equ                      1
        include pmgre.inc
        include driver.inc
        include display.inc
        include 8514.inc
        include assert.mac
        include palette.inc
        .list

        CPUMode 386

        externFP    far_exclude         ; CURSORSC.ASM
        externFP    far_unexclude       ; CURSORSC.ASM
        externA     DOSHUGEINCR

RLE_CLIPPED     equ     00000001b       ;clipping is required

sBegin  Data
        externW     BoardMaxY           ;max real addressable y on board
sEnd

sBegin  PtrData
        externB     screen_busy         ;cursor exclusion flag
sEnd    PtrData

sBegin  Code

        assumes cs, Code

        externW     CodeData                ; local data segment access
        externW     MyPtrCodeData

        assumes ds, nothing
        assumes es, nothing

cProc   RLEDrawBits, <NEAR, PUBLIC, WIN, PASCAL>, <si, di>

        parmD   pddcDst                           ;Destination ddc
        parmW   xDst                              ;Destination x origin
        parmW   yDst                              ;Destination y origin
        parmW   xClipLft                          ;Source x origin
        parmW   yClipBot                          ;Source y origin
        parmW   cxExt                             ;x extent of the BLT
        parmW   cyExt                             ;y extent of the BLT
        parmD   lpRLEbits                         ;pointer to RLE encoded buffer
        parmD   ulScheme                ;the compression scheme
        parmD   lpClrTab                ;the color mapping table

        localW  xDstOrg                 ;the screen's x origin
        localW  xClipRgt                          ;right of clip rectangle
        localW  yClipTop                          ;bottom of the clip rectangle
        localW  X                                 ;current X on display surface
        localW  Y                                 ;current Y on display surface

        localB  fbSurfaceFlags                    ;defines the following flags
        localW  usBoardHeight

        localW  pfnSetPixel             ;point to fn. to output pixels

cBegin

        cld

        mov     ds,CodeData
        assumes ds,Data
        mov     ax,BoardMaxY
        mov     usBoardHeight,ax

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

rdb_src_rect:
        xor     ax,ax                   ;the RLE starts from origin(0,0)
        mov     X,ax                    ;start X coordinate
        mov     Y,ax                    ;start Y coordinate
        mov     ax,xClipLft             ;the left edge
        add     ax,cxExt
        mov     xClipRgt,ax             ;the right edge
        mov     ax,yClipBot             ;the top edge
        add     ax,cyExt
        mov     yClipTop,ax             ;the Bottom edge
        dec     ax


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


rdb_cursor_exclude:
        mov     si,cxExt
        mov     di,cyExt
        dec     si                                ;Make extents inclusive of last point
        dec     di
        mov     cx,xDst                 ;Set left
        mov     dx,yDst                 ;Set top
        add     si,cx                             ;Set right
        add     di,dx                             ;Set bottom
        cCall   far_exclude                       ;Exclude the area from the screen


;/*
;**  Setup as many 8514's parameters as possible.                               ;
;*/

rdb_init_screen:
        GrabScreen  RLEDrawBits         ; don't let cursor operations kill us
        cCall   rdb_Setup_8514

;/*
;** The Y 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 (xDst,yDst+cyExt-1). Set up the start X and Y coordinates.       ;
;*/

rdb_dst_rect:
        mov     ax,yDst                 ; get the Y origin (top scan)
        add     ax,cyExt                ; move it to the bottom of scan
        add     ax,yClipBot             ; move it again to the first scan
        dec     ax
        mov     yDst,ax                 ; adjusted Y origin

        mov     ax,xDst                 ; get the X origin (leftmost pel)
        sub     ax,xClipLft             ; move it to the first pel
        mov     xDst,ax                 ; adjusted X origin
        mov     xDstOrg,ax


;/*
;**  Decode and output pels to the screen.                                      ;
;*/

rdb_decode_rle:
        lds     si, lpRLEbits                     ;DS:SI --> RLE bitmap
        assumes ds,nothing
        mov     gs, lpClrTab.sel        ;selector of the color mapping table
        assumes gs,nothing

        cmp     ulScheme,BCA_RLE8
        jne     short @F
        cCall   DecodeRLE8
        jmp     short rdb_done
@@:
        cCall   DecodeRLE4

rdb_done:
        ReleaseScreen RLEDrawBits                ;allow cursor to do what it has to
        cCall   far_unexclude
        mov     ax,1                             ;always TRUE => no failure

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = rdb_Setup_8514
;*
;* DESCRIPTION   =
;*
;*     This routine sets the 8514's X, Y, DX, and DY registers to the
;*     dimensions of the rectangle to be drawn and issues the actual draw     
;*     command.  Also, sets 8514's mode, and mix registers.  Checks that FIFO 
;*     has enough room to accept incomming data                               
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   rdb_Setup_8514, <NEAR, PUBLIC>
cBegin  <nogen>

;/*
;**  Since our source and destination have already been pre-clipped we do not
;**  have to worry about GP faults locally or coordinate wrap on the board.
;**  Therefore, we set up the board clip rectangle here so that it need not
;**  be done anywhere in the loop.
;** 
;**  In addition, we can assume that we are always writing to/from all planes,
;**  since PM doesn't seem to utilize plane enable as a concept, and we do not
;**  use it in the blt. Therefore, go ahead and enable all planes for reading
;**  and / or writing.
;*/

        WaitQ   6                       ; set up scissor rectangle
        Mov     Ax,xDst                 ; min left x
        Or      Ah,High XMIN_2DECODE
        .errnz  Low XMIN_2DECODE
        outwQ   XMIN                    ; x clip bounds is clipped rect bounds
        And     Ah,Not (High DECODE_FIELD)
        .errnz  Low DECODE_FIELD
        Add     Ax,cxExt                ; max right x
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX
        outwQ   YMIN,YMIN_2DECODE       ; min y is always 0
        Mov     Ax,usBoardHeight        ; max y is max addressable y
        Or      Ah,High YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX
        Mov     Al,0ffh                 ; all planes enabled for r/w
        outbQ   READ_ENABLE,Al
        outbQ   WRITE_ENABLE,Al

;/*
;** Before we start writing to the 8514 we want to make sure that the input
;** queue is empty, so that we don't need to check each time we write something
;*/

        WaitQ   4

;/*
;**  Set mode to host supplied data
;*/

        outwQ   MODE,MODE_2DECODE+MD_PS_VAR

;/*
;** Set the forground and background mix register to source-copy with host
;** supplied data


        mov     ax,FUNC_2OP_VAR+FUNC_S
        outwQ   FUNCTION_1
        outwQ   FUNCTION_0

; Set Y extent to one scanline

        xor     ax,ax
        outwQ   LY

        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = ReadRLE   
;*
;* DESCRIPTION   = Reads a byte from a encoded RLE buffer.  This function 
;*                 will take care of segment crossing.                                        ;
;*                                                                            
;*                 Registers destroyed: flags
;*                                                                            
;* INPUT         = DS:SI   pointer into RLE buffer 
;*                 
;* OUTPUT        = AL  = Byte from buffer
;*                 DS:SI   incremented    
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   ReadRLE,<NEAR,PUBLIC>

cBegin  <nogen>

        lodsb
        or      si, si
        jz      ReadRLENextSeg
        ret

ReadRLENextSeg:
        mov     si, ds
        add     si, DOSHUGEINCR
        mov     ds, si
        assumes ds,nothing
        xor     si, si
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = SetPixel8
;*
;* DESCRIPTION   = Sets the current pixel at <X,Y> if it is within the clipped
;*                 rectangle, otherwise do nothing.
;*
;*                 Registers destroyed: flags
;*                                                                            
;* INPUT         = DX      Pixel Port        
;*                 AX      Pixel Color
;*                 CX      # of output pels
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   SetPixel8,<NEAR,PUBLIC>

cBegin  <nogen>

SetPixel8Loop:
        out     dx, ax
        loop    SetPixel8Loop

SetPixel8Exit:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = SetPixel4
;*
;* DESCRIPTION   = Sets the current pixel at <X,Y> if it is within the clipped
;*                 rectangle, otherwise do nothing.
;*
;*                 Registers destroyed: flags
;*                                                                            
;* INPUT         = DX      Pixel Port        
;*                 AX      Pixel Color
;*                 CX      # of output pels
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   SetPixel4,<NEAR,PUBLIC>

cBegin  <nogen>

SetPixel4Loop:
        xchg    al,ah
        out     dx, ax
        loop    SetPixel4Loop

SetPixel4Exit:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = BoardWriteStartup
;*
;* DESCRIPTION   = sets the 8514's registers to `horizontal line, user defined
;*                 data' Routine does clipping in Y
;*                 
;*                 Registers destroyed: AX
;*                                                                            
;* INPUT         = DI = length of scanline to do.     
;*                 DX = 8514's user defined data port 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   BoardWriteStartup,<NEAR,PUBLIC>

cBegin  <nogen>

        or      di, di
        jz      short ZeroLengthExit

        WaitQ   3
        outwQ   X0, xDst                ;the current abscissa
        outwQ   Y0, yDst                ;the current screen scan
        mov     ax, di
        dec     ax
        outwQ   LX, ax                  ;the segment span

CMDCOLOR        =       (\
                         CMD_C_HRECT+CMD_BYTEORDER+CMD_FV_VAR+CMD_DY+\
                         CMD_DX+CMD_MA_ACCESS+CMD_PA_ONE+CMD_RW_W\
                        )

;/*
;** Make sure there is enough room for 1st data item on top of write command
;** befare issue proper write command
;*/

        WaitQ   2
        outwQ   CMD_FLAGS,CMDCOLOR

;/*
;**  Leave the Pixel Port Address in DX
;*/

        mov     dx, COLOR_0

ZeroLengthExit:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = BoardWriteStartup
;*
;* DESCRIPTION   = returns the X extent of the next scanline in DI for 8 bpp 
;*                 
;*                 Registers destroyed: AX,flags
;*                                                                            
;* INPUT         = DS:SI   the current 8bpp RLE record 
;* OUTPUT        = DI      the next segment span       
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   GetRunLength8,<NEAR,PUBLIC>

cBegin  <nogen>

        xor     di, di                        ;accumulate length in di
        mov     ax, CodeOFFSET SetPixel8Exit  ; assume clipped
        mov     cx, Y
        cmp     cx, yClipBot
        jb      short GRLExit

        push    ds
        push    si                                ;save current position to RLE bits

GetRunLengthLoop:
        xor     ax, ax
        cCall   ReadRLE                           ;this must be a count
        or      al, al                            ;is it a count = 0 special case?
        jz      short GRLEscapeCode               ;yes, go to Delta Encoding

        add     di, ax                            ;update current run length
        cCall   ReadRLE                           ;skip over color index
        jmp     short GetRunLengthLoop            ;do the next run

GRLEscapeCode:
        call    ReadRLE                           ;get the kind of excape into AL
        cmp     al, 3                             ;is it an absolute run?
        jb      short GRLDone

        add     di, ax                            ;yes, absolute mode run, update length
        shr     ax, 1
        adc     ax, 0
        shl     ax, 1                              ;align it to word boundary

GRLSkipIndices:
        add     si, ax                            ;skip over absolute color indices
        jnc     short GetRunLengthLoop            ;may span a segment boundary
        mov     ax, ds
        add     ax, DOSHUGEINCR
        mov     ds, ax
        jmp     short GetRunLengthLoop

GRLDone:
        pop     si
        pop     ds
        mov     ax, CodeOFFSET SetPixel8

GRLExit:
        mov     pfnSetPixel, ax
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = DecodeRLE8
;*
;* DESCRIPTION   = 
;*                                                                            
;*     This routine fetches runs from the source and puts them to the screen  
;*                                                                            
;*     Calls:
;*          GetRunLength    -- get segment span
;*          BoardWriteSetup -- set up 8514 registers for next write
;*                                                                            
;* INPUT         = DS:SI --> RLEBits 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   DecodeRLE8,<NEAR,PUBLIC>

cBegin  <nogen>

        mov     bx, lpClrTab.off                 ;now gs:bx --> color translation table

;/*
;** Get the segment span of the current scan so we can setup the 8514 HW once
;** for this scan
;*/

DecodeRLEMainLoop:
        cCall   GetRunLength8                     ;DI=length of scanline to do
        cCall   BoardWriteStartup                 ;now we're ready to draw to the screen
        xor     ax,ax

;/*
;**  Determine the type of the next RLE record
;*/

DRLEMainLoop:
        cCall   ReadRLE                           ;this better be a count
        or      al, al
        jz      short DREscapeCode

;/*
;**  It is the Encoded type
;*/

        mov     cx, ax                            ;CX: count
        add     X, cx                             ;update current X position
        add     xDst,cx
        cCall   ReadRLE                           ;AX: color value
        xlat    gs:[bx]                           ;use color translate table
        cCall   [pfnSetPixel]                     ;copy the run to the screen
        jmp     short DRLEMainLoop                ;go do the next run

;/*
;** It is one of the escape mode. Determine the specific type from the
;** next byte.
;*/

DREscapeCode:
        cCall   ReadRLE                           ;get the type of escape we have here
        or      al, al                            ;is it the end of line?
        jz      short DecodeRLEEOL
        cmp     al, 3                             ;is it an absolute run?
        jb      short DRMiddleTwo                 ;nope.

;/*
;**  It is an absolute code.
;*/

        mov     cx, ax                            ;AX = the # of pels in this run
        add     X, ax                             ;update abscissa to the end of this run
        add     xDst,ax
        push    ax                                ;save this count until after this loop
        mov     di,1                              ;output one pixel at a time

DRAbsoluteCopyLoop:
        cCall   ReadRLE                           ;fetch next pixel
        xlat    gs:[bx]                           ;apply DIB color translate table to it
        xchg    cx,di
        cCall   [pfnSetPixel]                     ;output it
        inc     cx
        xchg    cx,di
        loop    DRAbsoluteCopyLoop                ;do it for the entire run

        pop     ax                                ;AX: restored loop count
        test    al, 1                             ;was it even?
        jz      short DRLEMainLoop                ;yes, next run
        cCall   ReadRLE                           ;dummy read to remain word aligned
        jmp     short DRLEMainLoop                ;go do next run

;/*
;**  It is the end of line code. Reset the abscissa and move to the next scan
;*/

DecodeRLEEOL:
        mov     ax, xDstOrg                       ;kept current for delta encoding
        mov     xDst, ax
        mov     X,0
        dec     yDst                             ;Update Y position as well!
        inc     Y
        mov     ax,Y
        cmp     ax,yClipTop
        jb      short DecodeRLEMainLoop
        jmp     short ExitDecodeRLE


;/*
;** It is either the end of bitmap or delta mode. If delta, set the pel pointer
;** properly.
;*/

DRMiddleTwo:
        cmp     al, 1                             ;end of bitmap?
        je      short ExitDecodeRLE               ;yes, get out

        cCall   ReadRLE                           ;get delta X (unsigned)
        add     X, ax                             ;update our X position
        add     xDst, ax
        cCall   ReadRLE                           ;get delta Y (unsigned)
        sub     yDst, ax                          ;update Y.
        add     Y, ax
        mov     ax,yClipTop
        cmp     ax,Y
        ja      DecodeRLEMainLoop

ExitDecodeRLE:
        ret                                       ;get out now

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = GetRunLength4
;*
;* DESCRIPTION   = returns the X extent of the next scanline in DI for 4 bpp 
;*                                                                            
;*     Registers Destroyed:  AX,flags
;*     
;* INPUT         = DS:SI   the current 4bpp RLE record 
;* OUTPUT        = DI      the next segment span       
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   GetRunLength4, <NEAR, PUBLIC>

cBegin  <nogen>

        xor     di, di                            ;accumulate length in di
        mov     ax, CodeOFFSET SetPixel4Exit      ; assume clipped
        mov     cx, Y
        cmp     cx, yClipBot
        jb      short GRL4Exit

        push    ds
        push    si                                ;save current position to RLE bits
        xor     ax, ax

GetRunLength4Loop:
        cCall   ReadRLE                           ;this must be a count
        or      al, al                            ;is it a count = 0 special case?
        jz      short GRL4EscapeCode              ;yes, go to Delta Encoding

        add     di, ax                            ;update current run length
        cCall   ReadRLE                           ;skip over next two color indices
        jmp     short GetRunLength4Loop           ;do the next run

GRL4EscapeCode:
        cCall   ReadRLE                           ;get the kind of excape into AL
        cmp     al, 3                             ;is it an absolute run?
        jb      short GRL4Done

        add     di, ax                            ;yes, absolute mode run
        inc     ax                                ;round up to next even number
        shr     ax, 1                             ;divide it by two
        inc     ax                                ;now round this even count/2 to next
        and     al, 0feh                          ;even number
        add     si, ax                            ;skip over absolute color indices
        jnc     short GetRunLength4Loop           ;may span a segment boundary
        mov     cx, ds
        add     cx, DOSHUGEINCR
        mov     ds, cx
        jmp     short GetRunLength4Loop

GRL4Done:
        pop     si
        pop     ds
        mov     ax, CodeOFFSET SetPixel4

GRL4Exit:
        mov     pfnSetPixel, ax
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = DecodeRLE4
;*
;* DESCRIPTION   = 
;*                                                                            
;*     This routine fetches runs from the source and puts them to the screen  
;*                                                                            
;*     Calls:
;*          GetRunLength    -- get segment span
;*          BoardWriteSetup -- set up 8514 registers for next write
;*                                                                            
;* INPUT         = DS:SI --> RLEBits 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   DecodeRLE4, <NEAR, PUBLIC>
cBegin  <nogen>

        mov     bx, lpClrTab.off                  ;now gs:bx --> color translation table

DecodeRLE4MainLoop:
        cCall   GetRunLength4                     ;DI=length of scanline to do
        cCall   BoardWriteStartup                 ;now we're ready to draw to the screen

DRLE4MainLoop:
        xor     ax, ax
        call    ReadRLE                           ;this better be a count
        or      al, al
        jz      DR4EscapeCode

        mov     cx, ax                            ;CX: count
        add     X, ax                             ;update current X position
        add     xDst, ax
        cCall   ReadRLE                           ;AL: color values
        mov     ah, al
        shr     al, 4                             ;1st nibble in al
        xlat    gs:[bx]                           ;use DIB color translate table
        xchg    al, ah                            ;Xlated 1st pixel in ah
        and     al, 0fh
        xlat    gs:[bx]                           ;X-lated 2nd pixel in al
        cCall   [pfnSetPixel]                     ;copy the run to the screen
        jmp     short DRLE4MainLoop               ;go do the next run

DR4EscapeCode:
        cCall   ReadRLE                           ;get the type of escape we have here
        or      al, al                            ;is it the end of line?
        jz      short DecodeRLE4EOL
        cmp     al, 3                             ;is it an absolute run?
        jb      DR4MiddleTwo                      ;nope.

        mov     cx, ax                            ;absolute run mode.
        add     X, ax                             ;update X position
        add     xDst, ax
        push    cx
        mov     di,1                              ;output one pel at a time

DR4AbsoluteCopyLoop:
        cCall   ReadRLE                           ;fetch next pixel
        mov     ah, al
        shr     al, 4                             ;1st nibble in al
        xlat    gs:[bx]                           ;use DIB color translate table
        xchg    al, ah                            ;Xlated 1st pixel in ah
        and     al, 0fh
        xlat    gs:[bx]                           ;X-lated 2nd pixel in al
        xchg    cx,di
        cCall   [pfnSetPixel]                     ;output it
        inc     cx
        xchg    cx,di
        dec     cx                                ;update loop count
        jcxz    DRLE4AllignSrcPtr                 ;are we already done?
        xchg    cx,di
        cCall   [pfnSetPixel]                     ;output it to the screen
        inc     cx
        xchg    cx,di
        loop    DR4AbsoluteCopyLoop               ;do it for the entire run

DRLE4AllignSrcPtr:
        pop     cx                                ;restore initial loop counter
        inc     cx                                ;compute the number of bytes actually
        shr     cx, 1                             ;read
        mov     ax, cx                            ;save it in AX
        inc     ax                                ;word allign byte count
        and     al, 0feh
        cmp     ax, cx                            ;are we already word alligned?
        je      short DRLE4MainLoop               ;yes, go back to main loop
        cCall   ReadRLE                           ;force word allignment, do dummy read
        jmp     short DRLE4MainLoop               ;go do next run

DecodeRLE4EOL:
        mov     ax, xDstOrg                       ;kept current for delta encoding
        mov     xDst, ax
        mov     X, 0
        dec     yDst                              ;Update Y position as well!
        inc     Y
        mov     ax,Y
        cmp     ax,yClipTop
        jb      DecodeRLE4MainLoop
        jmp     short ExitDecodeRLE4

DR4MiddleTwo:
        cmp     al, 1                             ;end of bitmap?
        je      short ExitDecodeRLE4              ;yes, get out

        call    ReadRLE                           ;get delta X (unsigned)
        add     X, ax                             ;update our X position
        add     xDst, ax
        call    ReadRLE                           ;get delta Y (unsigned)
        sub     yDst, ax                          ;update Y.
        add     Y, ax
        mov     ax,yClipTop
        cmp     ax,Y
        ja      DecodeRLE4MainLoop

ExitDecodeRLE4:
cEnd

sEnd    Code

        public  rdb_src_rect
        public  rdb_cursor_exclude
        public  rdb_init_screen
        public  rdb_dst_rect
        public  rdb_decode_rle
        public  rdb_done

end
