;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
ifdef DCAF
        PAGE    ,132
        TITLE   EXPAND.ASM
;/*****************************************************************************
;*
;* SOURCE FILE NAME = EXPAND.ASM
;*
;* DESCRIPTIVE NAME = DCAF expansion code used by SetScreenBits.
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/22/92
;*
;* DESCRIPTION
;*
;* FUNCTIONS
;*              Planar4bppRectangle
;*              Packed4bppRectangle
;*              InvalidFormat
;*              DecompressScreenBits
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/22/92                     Created for DCAF 1.3
;*   07/01/92                     Ported to 32-bit for DCAF 2.0
;*
;*****************************************************************************/

        .xlist
        .386p

INCL_DDICOMFLAGS        equ     1
INCL_GRE_REGIONS        equ     1
INCL_GPIREGIONS         equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1
        include pmgre.inc
        include driver.inc
        include assert.mac
        include protos.inc
        include extern.inc

INCL_GPIERRORS          equ     1
        include pmerr.inc

        include dcafmac.inc
        .list

        .MODEL  FLAT
        ASSUME  CS:FLAT, SS:FLAT, DS:FLAT, ES:FLAT

;/*
;** These defines make the comparisons easier later on
;*/
planar    equ 1
packed_4  equ 4
packed_8  equ 8
packed_16 equ 16
planar2packed equ 2

;/*
;** We have a number of versions of ProcessOneRectangle for each of
;** the formats a driver supports.  They are all generated from a
;** single set of source.
;** All the labels are defined as locals since the macro is used more than
;** once.
;*/
ProcessOneRectangle_body macro format
        local   next_scan
        local   next_scan_relay
        local   within_a_scan
        local   next_cell
        local   not_next_scan
        local   not_mid_zero
        local   non_rle
        local   repeat_type
        local   on_first_plane
        local   last_exists
        local   count_in_eax
        local   enough_scans_left
        local   each_repeat
        local   pop_then_next_scan
        local   dual_repeat
        local   lastbut1_exists
        local   panic_exit
        local   done_all_scans
        local   final_exit
        local   next_seg
        local   small_bitmap
        local   segment_change
        local   src_segment_change
        local   no_src_change
        local   dest_segment_change
        local   seg_change


;/*
;** Set up so that @FLD8 and @FLD16 macros work dependant on the unit
;** size of the format this routine is working on.
;*/
if (format eq planar) or (format eq packed_4)
        INITFIELDSIZE    8
endif ; (format eq planar) or (format eq packed_4)
if (format eq planar2packed)      ;IBMJ
        INITFIELDSIZE    8
endif ; (format eq planar2packed)     ;IBMJ
if (format eq packed_8) or (format eq packed_16)
        INITFIELDSIZE    16
endif ; (format eq packed_8) or (format eq packed_16)

;/*
;** Some clarification of terminology may be in order here.
;**
;** A unit/field  - a byte for 4bpp formats, a word for all others
;** A cell        - a number of units representing a run of pels
;** (either an RLE run, a non compressed run, or a
;** repeat scanline run)
;** A scanline    - all the data for a line of screen/bitmap data
;** A scan        - a scanline if packed, or a plane if planar
;**
;** A full width scan or scanline, is the width of the bitmap.
;** If unqualified, a scan or scanline is the width of the rectangle.
;*/

;/*
;** We need our string instructions to increment
;*/
        cld

ifdef FIREWALLS
;/*
;** Set the previous pointers to NULL.
;** This allows us to double check the data we are passed - if
;** these are still null when we come to use tham then we have
;** been given a repeat line code in the       place.
;*/
        xor     eax,eax
        mov     pLastScanline, eax
        mov     pLastBut1Scanline, eax
endif ; FIREWALLS

;/*
;** Move some important values from the bitmap header into local
;** scope.
;** This is driver specific.
;*/
        mov     esi,pBitmap             ; Get the VGA surface definition
        ASSUME  ESI:PTR SURFACE
        mov     eax,[esi].sd_cbScan     ; Get index to next plane
        mov     cbScanDelta, eax

;/*
;** Process the rectangle, to determine how much work there is to do.
;*/
        mov     ebx, prcl
        ASSUME  EBX:PTR RECTL
        mov     eax, [ebx].rcl_xRight
        sub     eax, [ebx].rcl_xLeft

if (format eq planar)
;/*
;** Planar format (ie 4bpp) has 8 pels per unit (of a byte) on each scan
;*/
        shr     eax, 3                  ; divide by 8 (since 8 pels per byte)
endif ; (format eq planar)
if (format eq packed_4)
;/*
;** We need to store the number of pels for the unpacking call
;*/
        mov     cPels,eax
;/*
;** 4bpp packed format has 2 pels per unit (of a byte)
;*/
        shr     eax, 1                  ; divide by 2 (since 2 pels per byte)
endif ; (format eq packed_4)
        mov     cUnitsPerScan, eax

if (format eq packed_4)
;/*
;** The cbEndOfScanInc applies within a plane when on packed_4 data
;** so divide again by 4 (making 8 in total)
;** since within planar data there are 8 pels per byte.
;*/
        shr     eax, 2                  ; divide by 4 (since 8 pels per byte)
endif ; (format eq packed_4)

;/*
;** Having saved the number of units per scan, we now need to
;** change this number back to bytes for the next calculation
;*/
@FLD16 <add     eax,eax>

;/*
;** Find the increase from the end of one scan to the start of the next.
;*/
        mov     edx,cbScanDelta         ; bytes per full width scan
        sub     edx,eax                 ; subtract the amount processed
        mov     cbEndOfScanInc, edx

;/*
;** Find the number of scans to process
;*/
        mov     eax, [ebx].rcl_yTop
        sub     eax, [ebx].rcl_yBottom
if (format eq planar)
;/*
;** Planar format has 4 scans for each scanline in the passed rectangle
;*/
        shl     eax,2                   ; mult by 4 to go from lines to planes
endif ; (format eq planar)
if (format eq planar2packed)      ;IBMJ
;/*
;** Planar format has 4 scans for each scanline in the passed rectangle
;*/
        shl     eax,2                   ; mult by 4 to go from lines to planes
endif ; (format eq planar2packed)     ;IBMJ
        mov     cScansToDo, eax

;/*
;** Find the address of the start of the rectangle we are going to
;** write to.
;** The data is provided from the top of the rectangle down.
;** This is very driver specific.
;** (VGA version is based on code from pixel.asm)
;*/
        mov     eax,[esi].sd_cy
        sub     eax,[ebx].rcl_yTop      ; Have now flipped y coord

        mov     edi,[esi].sd_pBits      ; Load pointer to the bitmap bits
        mov     ebx,[esi].sd_dScan      ; Get bytes per scan
        mul     ebx                     ; Compute offset of start of scan
        add     edi,eax                 ; Add to start of bitmap

;/*
;** EDI -> start of the correct scan in the bitmap
;*/
        mov     ebx, prcl               ; Get the pointer to the rectl
        mov     eax,[ebx].rcl_xLeft     ; Get X coordinate
if (format ne planar2packed)      ;IBMJ
        shr     eax,3                   ; Compute byte offset from start of scan
endif ; (format ne planar2packed)     ;IBMJ
        add     edi,eax                 ; cx:di --> byte of pixel

;/*
;** EDI -> the byte holding the corner of the rectangle
;*/

;/*
;** Get the data buffer pointer
;*/
        mov     esi, pBuffer

;/*
;** This is the top of the each scan loop
;**
;** 32 bit EDI -> the leftmost unit of current scan
;** 32 bit ESI -> the current unit of compressed data
;*/
next_scan:
        cmp     cScansToDo, 0
        jz      done_all_scans

        mov     eax, cUnitsPerScan
if (format eq planar2packed)      ;IBMJ
 shr eax, 3
endif ; (format eq planar2packed)     ;IBMJ
        mov     cUnitsToDo, eax

;/*
;** Get the next unit to expand from the buffer.
;*/
        xor     eax,eax         ; zero the top half so we can use whatever
                                ; size of register we want and still get the
                                ; same value.

@FLD8  <lodsb>
@FLD8  <and     al,al>
@FLD16 <lodsw>
@FLD16 <and     ax,ax>

if (format eq packed_4)
        jz       repeat_type    ; zero unit means a repeat scanline unit
else
        jz      repeat_type     ; zero unit means a repeat scanline unit
endif ; (format eq packed_4)

;/*
;** We must keep our previous scanline pointers up to date.
;** NB. we use edx, to avoid changing the value in eax
;*/
if (format eq planar)
;/*
;** We should only do this on the first plane
;*/
        test    cScansToDo, 3
        jnz     within_a_scan
endif ; (format eq planar)
if (format eq planar2packed)      ;IBMJ
;/*
;** We should only do this on the first plane
;*/
        test    cScansToDo, 3
        jnz     within_a_scan
endif ; (format eq planar2packed)     ;IBMJ

        mov     edx,pLastScanline
        mov     pLastBut1Scanline,edx
        mov     pLastScanline,edi

if (format eq packed_4)
;/*
;** If we are handling packed (4bpp) data on the VGA then we
;** must expand the data into a buffer, then later unpack the
;** buffer into the planar format
;*/
        mov     pPlanar,edi     ; save the planar format destination
        lea     edi, pelbuffer
endif ; (format eq packed_4)
if (format eq planar2packed)      ;IBMJ
;/*
;** If we are handling packed (4bpp) data on the VGA then we
;** must expand the data into a buffer, then later unpack the
;** buffer into the planar format
;*/
        mov     pPacked,edi     ; save the planar format destination
        lea     edi, pelbuffer
endif ; (format eq planar2packed)     ;IBMJ

within_a_scan:
@FLD8  <and     al,al>
@FLD16 <and     ax,ax>
        js      non_rle

;/*
;** We have an RLE encoded run
;*/
        mov     ecx,eax                 ; this is the repeat count
        assert  ecx,LE,cUnitsToDo
        sub     cUnitsToDo, ecx
@FLD8  <lodsb>                          ; this is the byte to repeat
@FLD8  <rep     stosb>                  ; expand the run length
@FLD16 <lodsw>                          ; this is the byte to repeat
@FLD16 <rep     stosw>                  ; expand the run length

next_cell:
;/*
;** We move to the next cell.
;**
;** If we have completed a scan then we move to the next scan.
;** The last instruction to affect the flags before arriving at this
;** instruction was a 'sub cUnitsToDo, ax'
;** Thus the zero flag will be set if we have reached the end of
;** a scan, and can move to the next scan.
;*/

;;      cmp     cUnitsToDo, 0  ; unnecessary !
        jnz     not_next_scan
        dec     cScansToDo

if (format eq packed_4)
;/*
;** If we are handling packed (4bpp) data on the VGA then we
;** have just expanded the data into a buffer.
;** We must now unpack the buffer into the planar memory bitmap.
;**
;** Currently we have
;** edi -> the last byte we wrote in our temporary buffer
;** This is of no further use to us !
;** We reset edi to the start of the buffer which is far more useful.
;*/

;/*
;** We can't call UnPackBuffer directly...
;**     INVOKE  UnPackBuffer, pPlanar, ADDR pelbuffer, cPels, cbScanDelta
;*/

;/*
;** We now call the UnPackBuffer routine indirectly because its
;** address is loaded at run-time.
;*/
        INVOKE  PFNUnPackBuffer PTR pfnUnPackBuffer,
                              pPlanar, ADDR pelbuffer, cPels, cbScanDelta

        mov     edi, pPlanar            ; the saved start of this scanline
;/*
;** Move to the next scanline.
;*/
        mov     eax,cbScanDelta
        shl     eax,2                   ; mult by 4 since 4 planes
        add     edi,eax                 ; move to the next scanline
endif ; (format eq packed_4)
if (format eq planar2packed)      ;IBMJ
        test    cScansToDo, 3
        jnz     next_scan

 INVOKE PackBuffer8, pPacked, ADDR pelbuffer, cUnitsPerScan

 mov edi, pPacked
 add edi, cbScanDelta
endif ; (format eq planar2packed)     ;IBMJ

if (format eq planar)
;/*
;** Now we need to move to the next scan line.
;*/
        add     edi,cbEndOfScanInc
endif ; (format eq planar)

        jmp     next_scan

not_next_scan:
        xor     eax,eax         ; zero the top half so we can use whatever
                                ; size of register we want and still get the
                                ; same value.
@FLD8  <lodsb>
@FLD8  <and     al,al>                  ; set the flags
@FLD16 <lodsw>
@FLD16 <and     ax,ax>                  ; set the flags
ifdef FIREWALLS
        jnz     not_mid_zero
        rip     text,<Repeat encountered in mid scan>
        jmp     panic_exit
not_mid_zero:
endif ; FIREWALLS
        jmp     within_a_scan

non_rle:
        mov     ecx,eax
@FLD8  <and     ecx, 7fh>               ; clear the top bit to get the count
@FLD16 <and     ecx, 7fffh>             ; clear the top bit to get the count
        assert  ecx,LE,cUnitsToDo
        sub     cUnitsToDo, ecx
@FLD8  <rep     movsb>
@FLD16 <rep     movsw>
        jmp     next_cell

repeat_type:
;/*
;** We have some form of scanline repeat code.
;*/

if (format eq planar)
ifdef FIREWALLS
;/*
;** A repeat field should only come at the start of the first plane
;*/
        test    cScansToDo, 3
        jz      on_first_plane
        rip     text,<Repeat encountered not on first plane>
        jmp     panic_exit
on_first_plane:
endif ; FIREWALLS
endif ; (format eq planar)

@FLD8  <lodsb>                          ; next byte determines type of repeat
@FLD8  <and     al,al>
@FLD16 <lodsw>                          ; next word determines type of repeat
@FLD16 <and     ax,ax>
        jz      dual_repeat

ifdef FIREWALLS
        cmp     pLastScanline, 0
        jne     last_exists
        rip     text,<Repeat last encountered on first scan>
        jmp     panic_exit
last_exists:
endif ; FIREWALLS

;/*
;** We have a 'repeat last scanline' code
;*/
        push    esi     ; Save the buffer pointer

        mov     esi,pLastScanline

count_in_eax:
;/*
;** eax holds the number of times to repeat
;*/
        mov     ebx, eax                ; move the count to a safe register

if (format eq planar)
        shl     eax,2                   ; * 4 because cScansToDo counts planes
endif ; (format eq planar)
if (format eq planar2packed)      ;IBMJ
        shl     eax,2                   ; * 4 because cScansToDo counts planes
endif ; (format eq planar2packed)     ;IBMJ

ifdef FIREWALLS
        cmp     cScansToDo, eax
        jae     enough_scans_left
        rip     text,<Repeat gives too many scans>
        pop     esi                     ; clean the stack etc
        jmp     panic_exit
enough_scans_left:
endif ; FIREWALLS
        sub     cScansToDo, eax

;/*
;** This is VGA, we need to copy 4 planes of data for each scanline
;*/
        mov     ecx,cUnitsPerScan
if (format eq packed_4)
        ; cUnitsPerScan was pels / 2 (packed 4bpp) but now we want
        ; the number of bytes per scan which has 8 pels per byte
        shr     ecx,2                   ; pels / 2 / 4 = pels / 8
endif ; (format eq packed_4)
        mov     edx,ecx                 ; keep this in a register for reuse
        mov     eax,cbEndOfScanInc        ; get the increment between scans

each_repeat:
;/*
;** Update the previous scans pointers
;*/
        mov     pLastBut1Scanline,esi
        mov     pLastScanline,edi

;/*
;** VGA requires 4 planes of data to be repeated
;*/

if (format ne planar2packed)      ;IBMJ
;/*
;** Copy the first plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
;/*
;** Copy the second plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
;/*
;** Copy the third plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
endif ; (format ne planar2packed)     ;IBMJ

;/*
;** Copy the fourth plane
;*/
        rep     movsb

;/*
;** Exit the loop if we have done all the repeats
;*/
        dec     ebx
        jz      pop_then_next_scan

;/*
;** Reload ecx for the next pass through the loop
;*/
        mov     ecx,edx

;/*
;** Move to the next scanline
;*/
        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        jmp     each_repeat

pop_then_next_scan:
        pop     esi

        add     edi,cbEndOfScanInc
        jmp     next_scan

dual_repeat:
;/*
;** We have a 'repeat last 2 scanlines' code
;*/
@FLD8  <lodsb>                          ; find how many times to repeat
@FLD16 <lodsw>                          ; find how many times to repeat
        add     eax,eax                 ; dual requires twice as many lines

ifdef FIREWALLS
        cmp     pLastScanline, 0
        jne     lastbut1_exists
        rip     text,<Repeat last 2 encountered before third scan>
lastbut1_exists:
endif ; FIREWALLS

        push    esi     ; Save buffer pointer

        mov     esi,pLastBut1Scanline
        jmp     count_in_eax

panic_exit:
        mov     ax,PMERR_INV_IMAGE_FORMAT
        save_error_code

        xor     eax,eax
        jmp     final_exit

done_all_scans:
        mov     eax,esi

final_exit:

ENDM

ifdef  IBMJ        ;IBMJ

PackBuffer8 PROTO SYSCALL,
 pPacked  :DWORD,
 pPlanear :DWORD,
 nbScan  :DWORD

endif ;IBMJ        ;IBMJ

        .DATA

        PUBLIC  pelbuffer
pelbuffer  BYTE    1024 DUP (?)

ifdef  IBMJ        ;IBMJ
ALIGN 4
Packed16ToPacked256Table BYTE 000h, 004h, 002h, 006h
    BYTE 001h, 005h, 003h, 0f8h
    BYTE 007h, 0fch, 0fah, 0feh
    BYTE 0f9h, 0fdh, 0fbh, 0ffh

endif ;IBMJ        ;IBMJ

        .CODE


;--------------------------Internal-Routine-----------------------------;
;/*********************************************************************
;* ProcessOneRectangle                                                *
;*   (Planar4bppRectangle)                                            *
;*   (Packed4bppRectangle)                                            *
;*                                                                    *
;* These routines take one rectangle and expand it into an internal   *
;* bitmap.                                                            *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       EAX  -> next byte which will need processing
;* Error Returns:
;*       EAX = 0 if data was in unexpected form (probably corrupt)
;*       Error Logged
;* Registers Preserved:
;*       ESI,EDI,EBX,EBP,DS,ES,FS,GS
;* Registers Destroyed:
;*       EAX,ECX,EDX,FLAGS
;* History:
;*
;* Wed 22-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
Planar4bppRectangle PROC SYSCALL USES edi esi,
        pBuffer :DWORD,
        pBitmap :DWORD,
        prcl    :DWORD

LOCAL   cbScanDelta :DWORD,
        cScansToDo :DWORD,
        cUnitsToDo :DWORD,
        cUnitsPerScan :DWORD,
        pLastScanline :DWORD,
        pLastBut1Scanline :DWORD,
        cbEndOfScanInc :DWORD
ifdef  IBMJ        ;IBMJ
LOCAL   pPacked :DWORD
endif ;IBMJ        ;IBMJ

ifndef IBMJ        ;IBMJ
        ProcessOneRectangle_body planar
else  ;IBMJ        ;IBMJ
 mov ax, DEVCAPS_COLORS
 cmp ax, 256
 jne not_svga
 mov ax, SCREEN_CX
 cmp ax, 1040
 je not_svga
        ProcessOneRectangle_body planar2packed
 jmp @F
not_svga:
        ProcessOneRectangle_body planar
@@:
endif ;IBMJ        ;IBMJ
        ret

Planar4bppRectangle ENDP

;**********************************************************************

ALIGN 4
Packed4bppRectangle PROC SYSCALL USES edi esi,
        pBuffer :DWORD,
        pBitmap :DWORD,
        prcl    :DWORD

LOCAL   cbScanDelta :DWORD,
        cScansToDo :DWORD,
        cUnitsToDo :DWORD,
        cUnitsPerScan :DWORD,
        pLastScanline :DWORD,
        pLastBut1Scanline :DWORD,
        cbEndOfScanInc :DWORD,
        pPlanar :DWORD,
        cPels :DWORD

ifndef IBMJ        ;IBMJ
        ProcessOneRectangle_body packed_4
else  ;IBMJ        ;IBMJ
 mov ax, DEVCAPS_COLORS
 cmp ax, 256
 jne not_svga
 mov ax, SCREEN_CX
 cmp ax, 1040
 je not_svga
 int 3
 jmp @F
not_svga:
        ProcessOneRectangle_body packed_4
@@:
endif ;IBMJ        ;IBMJ
        ret

Packed4bppRectangle ENDP

;**********************************************************************

ALIGN 4
InvalidFormat PROC SYSCALL USES edi esi
        int     3
        ret

InvalidFormat ENDP

;/*
;** We have a table of rectangle processing routines.
;** There is a different routine for each of the possible compressed
;** formats that we may be passed.
;*/
ALIGN 4
RectProcessingTable:
        DWORD  Packed4bppRectangle     ; format word = 0
        DWORD  InvalidFormat           ; format word = 1
        DWORD  InvalidFormat           ; format word = 2
        DWORD  InvalidFormat           ; format word = 3
        DWORD  InvalidFormat           ; format word = 4
        DWORD  InvalidFormat           ; format word = 5
        DWORD  InvalidFormat           ; format word = 6
        DWORD  InvalidFormat           ; format word = 7
        DWORD  Planar4bppRectangle     ; format word = 8

        .erre  (GSB_OPT_4BPP + GSB_OPT_LINEAR)  eq 0
        .erre  (GSB_OPT_8BPP + GSB_OPT_LINEAR)  eq 1
        .erre  (GSB_OPT_16BPP + GSB_OPT_LINEAR) eq 2
        .erre  (GSB_OPT_4BPP + GSB_OPT_PLANAR)  eq 8



;--------------------------Internal-Routine-----------------------------;
;/*********************************************************************
;* DecompressScreenBits                                               *
;*                                                                    *
;* This routine takes the output from GetScreenBits and builds a      *
;* replica image into a bitmap, within the same area that was         *
;* originally recorded, allowing for format conversion.               *
;*                                                                    *
;* The VGA driver will only ever be passed 4bpp data.                 *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       EAX  = TRUE (1)
;* Error Returns:
;*       EAX  = FALSE (0)
;*       Error logged
;* Registers Preserved:
;*       ESI,EDI,EBX,EBP
;* Registers Destroyed:
;*       EAX,ECX,EDX,FLAGS
;* History:
;*
;* Wed 22-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
DecompressScreenBits PROC SYSCALL USES edi esi,
        hddc    :DWORD,
        hrgn    :DWORD,
        pBuffer :DWORD

LOCAL   pEnd    :DWORD,
        pBitmap :DWORD,
        rclLocal :RECTL,
        pfnProcess :DWORD

;/*
;** Let's get access to the actual data
;*/
        mov     edi, pBuffer
        ASSUME  EDI:PTR PACKETHDR

;/*
;** Calculate the data end
;*/
        mov     eax, [edi].phd_length
        add     eax, edi
        dec     eax             ; last byte used is start + length - 1
        mov     pEnd, eax

;/*
;** Find the format of this data.
;** The (device specific) higher entry function should check if
;** this device can handle this format.
;*/
        movzx   ebx, [edi].phd_format
        mov     eax, dword ptr RectProcessingTable[ebx*4]   ; dword entries
        mov     pfnProcess, eax

;/*
;** Move to the first rectangle
;*/
        add     edi, size PACKETHDR
        ASSUME  EDI:PTR RealRECTS

;/*
;** Get hold of the bitmap handle from the DC instance.
;*/
        mov     esi, hddc
        ASSUME  ESI:PTR DDC
        mov     esi, [esi].ddc_npsd
        ASSUME  ESI:PTR SURFACE
        mov     pBitmap, esi


each_rectangle:
;/*
;** For this loop we have the following registers
;** edi -> current (incremented) pBuffer value
;** esi -> bitmap (surface) definition
;*/

;/*
;** Check to see if we have got to the end of the buffer
;*/
        or      edi,edi         ; have we processed a full 64K of data ?
        jz      good_exit_relay
        cmp     edi,pEnd        ; have we passed the end of the data ?
        jbe     got_a_rectangle
good_exit_relay:
        jmp     good_exit_now

got_a_rectangle:
;/*
;** Check that the rectangle fits within the bitmap size
;*/
ifdef FIREWALLS
;/*
;** We assume that other code will ensure that all
;** rectangles are positive (since screen bounds must at
;** least be within the screen size!)
;*/
        xor     eax,eax
        cmp     [edi].rcs_xLeft, ax
        jl      invalid_rect
        cmp     [edi].rcs_yBottom, ax
        jl      invalid_rect
endif ;FIREWALLS
        mov     eax, [esi].sd_cx        ; bitmap width
        cmp     ax, [edi].rcs_xRight
        jl      invalid_rect
        mov     eax, [esi].sd_cy        ; bitmap height
        cmp     ax, [edi].rcs_yTop
        jl      invalid_rect

;/*
;** Repack the RealRECTS into a RECTL structure
;*/
        movsx   eax, [edi].rcs_xLeft
        mov     rclLocal.rcl_xLeft, eax
        movsx   eax, [edi].rcs_yBottom
        mov     rclLocal.rcl_yBottom, eax
        movsx   eax, [edi].rcs_xRight
        mov     rclLocal.rcl_xRight, eax
        movsx   eax, [edi].rcs_yTop
        mov     rclLocal.rcl_yTop, eax

;/*
;** Jump past the rectangle data.
;*/
        add     edi, size RealRECTS

;/*
;** Process this rectangle.
;*/
        INVOKE  PFNProcessRectangle PTR pfnProcess,
                edi,
                esi,
                ADDR rclLocal

        and     eax,eax         ; returns NULL ptr on an error
        je      exit_now

;/*
;** Put the returned pointer back into the registers we require
;*/
        mov     edi, eax

;/*
;** convert 4 plane bitmap to 8 plane bitmap, if device is ATLAS-256.
;*/

;/*
;** If we were passed a region handle, then we need to update it
;** NB. Will we be passed an option flag to say if this handle is to
;** be used or not ?
;*/
        cmp     hrgn,0
        jz      each_rectangle          ; no region so do the next rectangle

        INVOKE  PFNDefCombineRectRegion PTR pfnDefCombineRectRegion,
                0,             ; hdc
                hrgn,
                ADDR rclLocal, ; prcl
                hrgn,
                CRGN_OR,
                hddc,
                NGreCombineRectRegion

        .errnz  RGN_ERROR
        and     eax,eax
        jnz     each_rectangle

        jmp     exit_now

invalid_rect:
        mov     eax, PMERR_INV_RECT
        save_error_code
        xor     eax,eax

good_exit_now:
;/*
;** Return success
;*/
        mov     eax, 1
exit_now:
        ret

DecompressScreenBits ENDP

;--------------------------Internal-Routine-----------------------------;
;/*********************************************************************
;* Convert_4pl_8pl                                                    *
;*                                                                    *
;* Convert D.D.format 4 planes bitmap data to                         *
;* D.D.format 8 planes data.                                          *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       pBitmapInit -> conversion starting point
;*       iScan       -> scans to convert
;*       nbScan      -> bytes to convert in one svan line
;*       cbScan      -> size of a scan line (one plane)
;* Returns:
;*       None
;* Registers Preserved:
;*       EDI,EBP
;* Registers Destroyed:
;*       EAX,EBX,ECX,EDX,ESI,FLAGS
;* History:
;*
;* 21-Jul-1993         -by-    H.Muta
;*     Re-wrote it for DCAF.
;* 31-Mar-1992         -by-    N.Ichikawa
;*     Delete the portion of checking plane order.
;* 17-Feb-1992         -by-    N.Ichikawa
;*     Wrote it.
;*
;**********************************************************************
;*
;*
;*    1) This routine's function is shown below.
;*
;*
;*       [ before conversion ]                     [ after conversion ]
;*
;*      <--- nbScan bytes --->                    <--- nbScan bytes --->
;*     pBitmapInit
;*      |
;*      | D.D.format 4 plane                        D.D.format 8 plane
;*      +---------------------+                   +---------------------+
;*      |/////////////////////|                   |#####################|
;*      |---------------------|                   |---------------------|
;*      |/////////////////////|                   |#####################|
;*      |---------------------|                   |---------------------|
;*      |/////////////////////|  ------------->   |#####################|
;*      |---------------------|   Extend with     |---------------------|
;*      |/////////////////////|      COLOR        |#####################|
;*      |---------------------|    CONVERSION     |---------------------|
;*      |                     |                   |#####################|
;*      |---------------------|                   |---------------------|
;*      |                     |                   |#####################|
;*      |---------------------|                   |---------------------|
;*      |                     |     Repeated      |#####################|
;*      |---------------------|   nScan times     |---------------------|
;*      |                     |        .          |#####################|
;*      +---------------------+        .          +---------------------+
;*                                     .
;*      +---------------------+        .          +---------------------+
;*      |                     |        .          |                     |
;*      |---------------------|                   |---------------------|
;*      |                     |                   |                     |
;*
;*
;*    2) There are many logical operations in this routine,they are prepared
;*       to realize direct conversion from planer format (4 planes) to planer
;*       format (8 planes) without mediating packed-pixel format. Followings
;*       are the brief explanation on how to get the boolean expressions used
;*       in this routine.
;*
;*       Following figure shows color mapping from 4 planes to 8 planes.
;*
;*          [ 4 PLANES ]                       [ 8 PLANES ]
;*
;*          I   R   G   B            R0  R1  R2  G0   G1  G2  B0  B1
;*        -----------------        -----------------------------------
;*          0   0   0   0             0   0   0   0    0   0   0   0
;*          0   0   0   1             0   0   0   0    0   0   1   0
;*          0   0   1   0             0   0   0   1    0   0   0   0
;*          0   0   1   1             0   0   0   1    0   0   1   0
;*
;*          0   1   0   0             1   0   1   0    0   0   0   0
;*          0   1   0   1             1   0   1   0    0   0   1   0
;*          0   1   1   0             1   0   0   1    0   0   0   0
;*          0   1   1   1             1   0   0   0    0   0   0   0
;*
;*          1   0   0   0             1   0   0   0    1   0   0   1
;*          1   0   0   1             0   0   0   0    0   0   1   1
;*          1   0   1   0             0   0   0   1    1   1   0   0
;*          1   0   1   1             0   0   0   1    1   1   1   1
;*
;*          1   1   0   0             1   1   1   0    0   0   0   0
;*          1   1   0   1             1   1   1   0    0   0   1   1
;*          1   1   1   0             1   1   1   1    1   1   0   0
;*          1   1   1   1             1   1   1   1    1   1   1   1
;*        -----------------         ----------------------------------
;*
;*       At first, paying attention to corresponding between I,R,G,B and R0.
;*
;*       As shown right, to get the output     [ 4 PLANES ]        [ 8 PLANES ]
;*       of R0 from four inputs I,R,G,and
;*       B, next boolean expression will       I   R   G   B            R0
;*       be needed.                          -----------------        ------
;*                                             0   0   0   0             0
;*          R0 =  ~IR~G~B  <--------------+    0   0   0   1             0
;*              + ~IR~GB   <------------+ |    0   0   1   0             0
;*              + ~IRG~B   <----------+ | |    0   0   1   1             0
;*              + ~IRGB    <--------+ | | |
;*                                  | | | +--  0   1   0   0  - - - - -  1
;*              + I~R~G~B  <------+ | |  +---  0   1   0   1  - - - - -  1
;*                                | | +------  0   1   1   0  - - - - -  1
;*              + IR~G~B   <----+ | +--------  0   1   1   1  - - - - -  1
;*              + IR~GB   <---+ | |
;*              + IRG~B  <--+ | | +----------  1   0   0   0  - - - - -  1
;*              + IRGB  <-+ | | |              1   0   0   1             0
;*                        | | | |              1   0   1   0             0
;*   -(Notice)------      | | | |              1   0   1   1             0
;*  |               |     | | | |
;*  |   '+' -> OR   |     | | | +------------  1   1   0   0  - - - - -  1
;*  |   '~' -> NOT  |     | | +--------------  1   1   0   1  - - - - -  1
;*  |  none -> AND  |     | +----------------  1   1   1   0  - - - - -  1
;*  |               |     +------------------  1   1   1   1  - - - - -  1
;*   ~~~~~~~~~~~~~~~                         -----------------         -----
;*
;*      Making it more simple expression, it will be,
;*
;*          R0 = ~IR(~G~B+~GB+G~B+GB) + I~R~G~B + IR(~G~B+~GB+G~B+GB)
;*
;*             = (~IR + IR)(~G~B+~GB+G~B+GB) + I~R~G~B
;*
;*             = ( R( ~I + I ))( ~G( ~B + B ) + G( ~B + B )) + I~R~G~B
;*
;*             =   R ( ~G + G ) + I~R~G~B    ( because of "( X + ~X ) = 1" )
;*
;*             =   R + I~R~G~B
;*
;*             =   R + Z    ( define Z = I~R~G~B )
;*
;*      We can also get following expressions by applying the same way to each
;*      target planes.
;*
;*          R1  = IR
;*
;*          R2  = ~IR~G + IR
;*              = ~IR~G + R1         ( able to use R1 )
;*
;*          G0  = G ~(RB) +  IRGB
;*              = GX + IRGB          ( define X = ~(RB) )
;*              = G( X + IRB )
;*              = G( X + R1 B )      ( able to use R1 )
;*
;*          G1  = IG + I~R~G~B
;*              = G2 + I~R~G~B       ( able to use G2 )
;*              = G2 + Z
;*
;*          G2  = IG
;*
;*          B0  = ( ~R + ~IR~G + IR )B
;*              = ( ~R + R2 )B       ( able to use R2 )
;*
;*          B1  = IB + I~R~G~B
;*              = IB + Z
;*
;*      As mentioned before, this way allows direct conversion between 4 planes
;*      and 8 planes of D.D.format, and additionally allows to calculate DWORD
;*      operation at the time of converting. For fast processing, this routine
;*      was described with this logic.
;*
;*
;*********************************************************************/
   ; 
   ;  Following logical operations
   ;   assume  eax->R, ebx->G, ecx->B, edx->I.
   ; 
                                        ;     general purpose register.
   ; 
   ;  Following logical operations
   ;   assume  al->R, bl->G, cl->B, dl->I.
   ; 
                                        ;     general purpose register.
   ; 
   ;  Following logical operations
   ;   assume  eax->R, ebx->G, ecx->B, edx->I.
   ; 
   ; 
   ;  Following logical operations
   ;   assume  al->R, ah->G, bl->B, bh->I.
   ; 

ifdef  IBMJ        ;IBMJ
ALIGN 4
PackBuffer8 PROC SYSCALL USES esi,
 pPacked  :DWORD,
 pPlanear :DWORD,
 nbScan  :DWORD

 mov esi,pPlanear
 mov edi,pPacked
 mov ebx,nbScan
 shr ebx,3
 push ebp
 mov ebp,ebx

pb8_next_byte:
        mov     cl,byte ptr [esi]               ; Plane 0
        mov     ch,byte ptr [esi+ebx]           ; Plane 1
        mov     dl,byte ptr [esi+ebx*2]         ; Plane 2
        add     esi,ebx
        mov     dh,byte ptr [esi+ebx*2]         ; Plane 3
        sub     esi,ebx
 inc esi

 rept 8
 xor eax,eax
 add dh,dh
 adc al,al
 add dl,dl
 adc al,al
 add ch,ch
 adc al,al
 add cl,cl
 adc al,al
 mov al,Packed16ToPacked256Table[eax]
 stosb
 endm

 dec bp
 jnz pb8_next_byte

pb8_all_done:
 pop ebp
        ret

PackBuffer8 ENDP
endif ;IBMJ        ;IBMJ

endif ; DCAF

end
