;*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 = BMC_ETI.ASM
;*
;* DESCRIPTIVE NAME = Handles bitmap conversions
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/16/87
;*
;* DESCRIPTION  Handles bitmap conversions, from external
;*              formats to internal formats                           
;*              There are four standard bitmap formats.  All device drivers
;*              are required to be able to translate between any of these
;*              formats and their own internal formats. The standard formats
;*              are as follows:
;*       
;*                                    Bitcount                 Planes
;*                                    --------                 ------
;*                                        1                      1
;*                                        4                      1
;*                                        8                      1
;*                                       24                      1
;*       
;*              These formats are chosen because they are identical or similar
;*              to all formats commonly used by raster devices.  Only single
;*              plane formats are standard, but it is very easy to convert these
;*              to any multiple plane format used internally by a device.
;*       
;*              The pixel data is stored in the bitmap in the order of the co-
;*              ordinates as they would appear on a display screen.  That is,
;*              the pixel in the lower left corner is the first in the bitmap.
;*              Pixels are scanned to the right and up from there.  The first
;*              pixel's bits are stored beginning in the lowest order bits of
;*              the first byte.  The data for pixels in each scan line is packed
;*              together tightly.  Each scanline, however, will be padded at the
;*              end so that each scan line begins on a DWORD boundary.
;*             
;*
;* FUNCTIONS    bmc_ext_to_int  
;*              eti_1
;*              eti_4
;*              eti_8
;*              eti_24
;*              get_color
;*              CreateColorTable
;*              MungeColorTable_41
;*              GetNextDsSelector
;*              CopyE1I1_0s
;*              CopyE1I1_1s
;*              CopyE1I1_0s_1s
;*              CopyE1I1
;*              CopyE1I1_Invert
;*              CopyE1I8
;*              CopyE4I1
;*              CopyE4I8
;*              CopyE8I1
;*              CopyE8I8
;*              CopyE24I1
;*              CopyE24I8
;*
;* NOTES         NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/12/87                     Walt Moore [waltm] Created.
;*   11/09/87                     Bob Grudem [bobgru] Internal color bitmaps
;*                                always use interleaved (i.e. huge)
;*                                scanline format.
;*
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GRE_BITMAPS        equ                      1
INCL_GPIBITMAPS         equ                      1
INCL_GPILOGCOLORTABLE   equ                      1
        include pmgre.inc
DINCL_BITMAP            equ                      1
        include driver.inc
        include display.inc
        include assert.mac
        include bmi2.inc
        include njmp.mac
ifdef PALMGR
        include palette.inc
endif
        .list
        CPUMode 286


        errcode <INV_SCAN_START,INV_INFO_TABLE,INV_LENGTH_OR_COUNT>

        externA DOSHUGEINCR                       ;Inc to next 64K of huge local segment


;/*
;** The CAN_CROSS_SEG flag is overlayed on top of the sd_fb flag taken
;** from the surface definition of the bitmap.  SD_DEVICE must be null
;** else we don't have a bitmap.
;*/

CAN_CROSS_SEG   Equ     SD_DEVICE                ;User's buffer will cross seg boundary


sBegin  Data
        externW npbmcColor                        ; color bitmap info
ifdef PALMGR
        externB devpalDefault
        externD phwpal
endif
sEnd

        externFP far_rgb_to_ipc                   ;phy16clr.asm
        externFP far_check_bitmap_info            ;bmsup.asm
ifdef PALMGR
        externFP far_rgb_to_ipc_with_pal         ;colormat.asm
        externFP MapDownPaletteIndex              ;colormat.asm
endif

page
sBegin  Bitmap
        assumes cs,Bitmap

        externW  BitmapData


;/*
;** anpfnPreProc is the dispatch table for the function to perform
;** any preprocessing required for the given format
;*/

anpfnPreProc    Label   Word
        Dw      eti_1
        Dw      eti_4
        Dw      eti_8
        Dw      eti_24
page

;/***************************************************************************
;*
;* FUNCTION NAME = bmc_ext_to_int 
;*
;* DESCRIPTION   = Bitmap conversion, external format to internal format                
;*                                                                                      
;*                 This is the driving routine for bitmap conversions from our          
;*                 internal formats to the external formats which we support.           
;*
;*                 Registers Preserved:    
;*                       SI,DI,BP,DS       
;*                 Registers Destroyed:    
;*                       AX,BX,CX,DX,FLAGS 
;*
;* INPUT         = npbm:DWORD 
;*                 pBuf:DWORD 
;*                 iStart:DWORD
;*                 pbmi:DWORD   
;*                 cyScans:DWORD,
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = # of scanlines translated 
;* RETURN-ERROR  = DX:AX = -1  
;*
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

cProc   bmc_ext_to_int,<NEAR,PASCAL,PUBLIC,NODATA,NONWIN>,<SI,DI,DS>

        parmW   npbm                              ; Bitmap
        parmD   pbmi                              ; -> Pointer to info block
        parmD   pBuf                              ; -> buffer of source bits
        parmD   cyScans                           ; Number of scans to copy
        parmD   iStart                            ; First scan to copy
ifdef PALMGR
        parmD   pPal                              ; target palette
        parmD   lpddc
endif

        localW  ScansCopied                       ; Number of scanlines copied
        localW  ScanCount                         ; Number of scanlines to copy
        localW  BitmapHeight                      ; Height of the bitmap in scans
        localD  lp_bits                           ; Pointer to the actual bits
        localW  NextScan                          ; Index to next scan line
        localW  ScansPerSeg                       ; Scanlines per segment
        localW  PrevOffset                        ; Offset of last scan, previous segment
        localW  HugeScansLeft                     ; Count of scans left in huge segment
        localW  BufferAdjust                      ; Alignment for each scan of buffer
        localW  ScanPixels                        ; Width in pixels of the bitmap
        localW  EtiProc                           ; Routine which xlates full bytes
        localD  SrcScanLen                        ; length of one buffer scanline
        localB  fbsd                              ; sd_fb local copy
        localW  ColorsMask                        ; for CreateColorTable
        localV  ColorXlate,256                    ; color translation table
        localW  rgb_size                ; old = 3 bytes, new = 4 bytes
ifdef PALMGR
        localB  fbPal
ETI_PALETTE     equ     00000001b                ; palette is selected into DC
ETI_PAL_INDICES equ     00000010b                ; color table contains palette indices
ETI_MONO        equ     00000100b                ; need mono bit calculated
endif
cBegin

ifdef   FIREWALLS
        Mov     Ds,BitmapData
        assumes Ds,Data
        Mov     Bx,npbm
        Cmp     [Bx].bm_sd.sd_usId,SURFACE_IDENT
        Jne     eti_not_a_bitmap
        Test    [Bx].bm_sd.sd_fb,SD_DEVICE
        Jz      eti_its_a_Bitmap
eti_not_a_bitmap:
        rip     text,<Bitmap Conversions - Surface is not a bitmap>
eti_its_a_Bitmap:
endif

        Mov     Ds,BitmapData
        assumes Ds,Data
        Cld
        Xor     Ax,Ax
        Mov     ScansCopied,Ax


;/*
;** Validate the parameters passed in.  We will only support the standard
;** formats.  We will not return bits in a device dependant format.  They
;** cannot give us bogus numbers for the start scan and count.
;*/

        mov     bx,PMERR_INV_SCAN_START ;The starting scan must be 0-65535
        cmp     iStart.hi,ax
        jne     eti_log_error
        mov     bx,PMERR_INV_LENGTH_OR_COUNT
        cmp     cyScans.hi,ax
        je      eti_numbers_ok
eti_log_error:
        xchg    ax,bx
        save_error_code
        mov     ax,-1
eti_get_out:
        jmp     eti_exit

eti_xfered_all_relay:
        jmp     eti_xfered_all

eti_numbers_ok:
        or      ax,cyScans.lo
        jz      eti_xfered_all_relay
        Les     Bx,pbmi                           ;Validate bitmap info structure
        assumes Es,nothing
        mov     cx,1                    ;signal for maximum check
        Call    far_check_bitmap_info
        Mov     Bx,PMERR_INV_INFO_TABLE
        Jcxz    eti_log_error

ifdef FIREWALLS
        Cmp     Ax,6                              ;We should always get back 0,2,4,6
        Jbe     @F
eti_cbi_failed:
        rip     text,<check_bitmap_info returned an illegal value>
@@:
        Test    Al,1
        Jnz     eti_cbi_failed
endif
        Xchg    Ax,Bx
        Mov     Si,anpfnPreProc[Bx]              ;Save preprocessor's address

ifdef PALMGR

        CPUMode 386
        xor     ax,ax
        mov     fbPal,al                          ;0 ==> default palette
        mov     di,DataOFFSET devpalDefault
        mov     dx,[di].devpal_pPalSeg.lo
        cmp     dx,pPal.lo
        jne     eti_have_pal
        mov     dx,[di].devpal_pPalSeg.hi
        cmp     dx,pPal.hi
        je      eti_check_color_encoding
eti_have_pal:
        or      fbPal,ETI_PALETTE
eti_check_color_encoding:
ifdef FIREWALLS
        mov     ax,es
        assert  ax,E,<pbmi.hi>
endif
        mov     bx,pbmi.lo
        cmp     es:[bx].bmi2_cbFix,bmi2_ulColorEncoding
        jbe     eti_fbPal_set_up
        cmp     es:[bx].bmi2_ulColorEncoding,BCE_PALETTE
        jne     eti_fbPal_set_up
        test    fbPal,ETI_PALETTE
        mov     bx,PMERR_INV_INFO_TABLE
        njz     eti_log_error
        or      fbPal,ETI_PAL_INDICES
eti_fbPal_set_up:
endif
        CPUMode 286

;/*
;** Copy the bitmap data as necessary to local frame storage
;*/

        Mov     Di,npbm
        Mov     Ax,[Di].bm_sd.sd_cx
        Mov     ScanPixels,Ax
        Mov     Ax,[Di].bm_sd.sd_cy
        Mov     BitmapHeight,Ax
        Mov     Al,[Di].bm_sd.sd_fb              ;Color format, huge, CAN_CROSS_SEG
        Mov     fbsd,Al                           ;  (if we set it)
        Mov     Cl,Al
        And     Ax,SD_NONNULL                     ;If a null surface, return
        njz     eti_get_out                       ;  0 scans copied.
        Mov     Ax,[Di].bm_sd.sd_pBits.off
        Mov     lp_bits.off,Ax
        Mov     Ax,[Di].bm_sd.sd_pBits.sel
        Mov     lp_bits.sel,Ax
        Mov     Bx,[Di].bm_sd.sd_dScan
        Mov     NextScan,Bx
        Test    Cl,SD_HUGE
        Jz      eti_isnt_huge_bitmap

;/*
;** The bitmap is a huge bitmap.
;*/

        Mov     Ax,[Di].bm_sd.sd_cySeg           ; # scanlines in a segment
        Mov     ScansPerSeg,Ax
        Add     Bx,[Di].bm_sd.sd_cbFill
        Neg     Bx
        Mov     PrevOffset,Bx                     ; save start of last scan in segment

eti_isnt_huge_bitmap:

;/*
;** We have gathered up most of the bitmap data necessary for doing
;** the conversion.  Compute the real starting scan Y and the number
;** of scanlines to copy.
;*/

        Mov     Cx,iStart.lo
        Mov     Bx,BitmapHeight
        sub     bx,cx                             ; if starting scan is outside bitmap
        njbe    eti_xfered_all_relay             ;  surface, then nothing to copy
                                                  ; compute number of scans to move
        Mov     Ax,cyScans.lo
        usmin_ax        bx
        Mov     ScanCount,Ax
        Mov     ScansCopied,Ax                    ; we will return this value


;/*
;** Now perform the format specific initialization.
;*/

        Mov     Di,pbmi.off
        assert  es:[di].bmi2_cbFix.hi,E,0
        mov     ax,es:[di].bmi2_cbFix.lo         ;ES:DI --> where color table is
        mov     rgb_size,(SIZE RGB)
        cmp     ax,SIZE BITMAPINFOHEADER
        je      eti_got_rgb_size
ifdef FIREWALLS
        assumes ds,Data
        mov     bx,es:[di].bmp2_cbFix.lo
        assert  bx,LE,64
        .errnz  (SIZE BITMAPINFOHEADER2)-64
        shr     bl,1
        assert  NC
        add     bx,DataOFFSET ok_cbFix
        mov     bl,[bx]
        assert  bl,NE,0
        assert  es:[di].bmp2_cbFix.hi,E,0
endif
        mov     rgb_size,(SIZE RGB2)
eti_got_rgb_size:
        add     di,ax
        call    si

;/*
;** Format specific initialization has been performed.  Compute
;** the real starting scan Y and the number of scanlines to copy.
;** If a huge bitmap and the scans to be copied are contained
;** within the same segment, then we can treat it as a normal bitmap.
;*/


        Mov     Ax,BitmapHeight                   ; invert the Y coordinate
        Sub     Ax,iStart.lo
        Dec     Ax
        Xor     Dx,Dx
        Test    fbsd,SD_HUGE
        Jz      eti_finish_y_calc


;/*
;** This is a huge bitmap.  Compute which segment the Y coordinate
;** is in.  Assuming that no huge bitmap will be bigger than two
;** or three segments, iteratively computing the value would be
;** faster than a divide, especially if Y is in the first segment
;*/

        Mov     Cx,DOSHUGEINCR
        Mov     Bx,ScansPerSeg

eti_huge_bitmap:
        Add     Dx,Cx                             ; show in next segment
        Sub     Ax,Bx                             ; see if in this segment
        Jnc     eti_huge_bitmap                  ; not in current segment, try next
        Sub     Dx,Cx                             ; show correct segment
        Add     Ax,Bx                             ; restore correct Y
        Inc     Ax
        Mov     HugeScansLeft,Ax                 ; # scans left in the segment
        Dec     Ax                                ; scan index for addr calculation
        Cmp     Ax,ScanCount                      ; if all bits are in the same segment
        Jle     eti_finish_y_calc                ; we'll skip huge bitmap stuff
        And     fbsd,not SD_HUGE

eti_finish_y_calc:
        Add     Dx,lp_bits.sel                    ;Dest is our bitmap
        Mov     Es,Dx
        assumes Es,nothing

        Mul     NextScan                          ; compute offset within the segment
        Add     Ax,lp_bits.off                    ; compute segment of the bits
        Xchg    Ax,Di

        Lds     Si,pBuf                           ; source is user's buffer (this pointer
        assumes Ds,nothing                        ; will never be loaded again)


;/*
;** See if we will cross a segment boundary in the user's buffer.
;** If so, special code will have to be used for copying any source
;** scan which would cross the boundary.
;*/

        Mov     Cx,ScanCount
        Mov     Ax,SrcScanLen.hi
        Mul     Cx
        Xchg    Ax,Bx
        Mov     Ax,SrcScanLen.lo
        Mul     Cx
        Add     Dx,Bx                             ;DX:AX = total bytes of buffer needed
        Add     Ax,Si
        Adc     Dx,0                              ;DX:AX = last address + 1
        Jz      eti_in_segment
        Or      fbsd,CAN_CROSS_SEG               ; can cross a segment boundary

eti_next_scan:
        Test    fbsd,CAN_CROSS_SEG               ; if buffer might cross a segment
        Jnz     eti_might_cross_seg              ; go check it out...

                                                  ; 'C' = 0 from Test above
eti_in_segment:                                   ; 'C' may = 1 if entered here

        Push    Di                                ; save bitmap scan start address
        Mov     Cx,ScanPixels                     ; pass # pixels to do'er
        Call    EtiProc                           ; process source scan
        Pop     Di                                ; recover dest scan start address
        Jc      eti_xfered_all                    ; segment crossing error...

        Dec     ScanCount
        Jz      eti_xfered_all                    ; transfered all scans

        Add     Si,BufferAdjust                   ; align source to dword boundary
        Jnc     @F                                ; no segment crossing from this...
        Call    GetNextDsSelector                ; advance to next segment
        Jc      eti_xfered_all                    ; make believe we finished
@@:

        Sub     Di,NextScan                       ; --> next bitmap scanline
        Test    fbsd,SD_HUGE                      ; if not a huge bitmap,
        Jz      eti_next_scan                     ; don't worry about updating segment

        Dec     HugeScansLeft                     ; any more scans in this segment?
        Jnz     eti_next_scan                     ; no, don't update bitmap pointer

        Mov     Ax,Es
        Sub     Ax,DOSHUGEINCR                    ; we're working from bottom up
        Mov     Es,Ax
        assumes Es,nothing

        Mov     Di,PrevOffset                     ; offset of last scan, previous segment
        Mov     Ax,ScansPerSeg
        Mov     HugeScansLeft,Ax                 ; this many scans in the segment

        Jmp     eti_next_scan


eti_might_cross_seg:

;/*
;** The buffer will cross a segment boundary.  If this scanline will
;** cross the segment, then we need to set the carry flag to inform the
;** do'er routine of the possibility.
;*/
 
        Mov     Ax,Si                             ; if the entire scan shows, then
        Xor     Dx,Dx                             ; we can use the normal code
        Add     Ax,SrcScanLen.lo
        Adc     Dx,SrcScanLen.hi                 ; SrcScanLen may be > 64K
        Jz      eti_in_segment                    ; it won't cross a segment boundary
        Stc                                       ; indicate segment crossing
        Jmp     eti_in_segment                    ; now continue...

eti_xfered_all:

        Mov     Ax,ScansCopied                    ; return number of scans copied

eti_exit:
        cwd
        fw_zero <Cx,Es>
cEnd

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE eti_1  
;*
;* DESCRIPTION   = Bitmap conversion, external format to internal 1 bit            
;*                                                                                 
;*                 This routine is responsible for all preprocessing for converting
;*                 from external 1 bit per pixel to internal formats               
;*
;*                 Registers Preserved:         
;*                       BP,DS,ES               
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = ES:DI --> where color table is 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

MonoConvert     Label   Word
;	Dw	CopyE1I1_0s			  ; same color, color is 0
	Dw	CopyE1I1_Invert 		  ; different colors, inverted
        Dw      CopyE1I1_1s                       ; same color, color is 1
        Dw      CopyE1I1_Invert                   ; different colors, inverted
        Dw      CopyE1I1                          ; different colors, as is

eti_1   Proc    Near


        Mov     Cx,2                              ; only two indices in source
        Call    CreateColorTable                 ; so need just two table entries

        Sub     Bx,Bx                             ; a zero

        Mov     SrcScanLen.hi,Bx                 ; src scan never > 64k bytes
        Mov     Ax,ScanPixels                     ; # pixels in a src scan
        Add     Ax,31                             ; round up to dword boundary
        And     Al,Not 31                         ; lo order bits are extraneous
        Shr     Ax,3                              ; now # bytes
        Mov     SrcScanLen.lo,Ax                 ; stuff src scan length in bytes

        Test    fbsd,SD_COLOR                     ; a color destination ?
        Jnz     eti_1_color                       ; yes...

;/*
;** Mono to mono.  Set up to copy as is, store all 0's, or invert,
;** depending on the two passed colors.
;*/

        Mov     Ax,Word Ptr ColorXlate           ; Al: index 0 IPC, Ah: index 1 IPC
        Xor     Al,Ah                             ; 0 where colors are the same
        Shr     Al,1                              ; create offset into function table
        .errnz  High MONO_BIT - 00000001b
        Rcl     Di,1
        Shr     Ah,1
        .errnz  High MONO_BIT - 00000001b
        Rcl     Di,2
        And     Di,00000110b
        Mov     Dx,MonoConvert[Di]               ; get -> 1:1 specialist routine

        Jmp     Short eti_1_have_proc

;/*
;** External mono to internal color bitmap. We have a choice internally of
;** going to a 4 or an 8 bit destination based on load-time configuration
;** parameters.
;*/

eti_1_color:

        Mov     Bx,ScanPixels                     ; # pixels in src scan
        Add     Bx,7                              ; round up to full byte
        Shr     Bx,3                              ; now # full bytes in src
        Neg     Bx                                ; # bytes needed to pad to dword
        And     Bx,00000011b                      ; in lo 2 bits

        Mov     Dx,BitmapOFFSET CopyE1I8  ; assume -> 1:8 specialist

eti_1_have_proc:

        Mov     BufferAdjust,Bx                   ; add to src -> after xlate operation
        Mov     EtiProc,Dx                        ; store -> do'er routine

        Ret

eti_1   Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE eti_4
;*
;* DESCRIPTION   = Bitmap conversion, external 4 bit to internal format                     
;*                                                                                          
;*                 This routine is responsible for all preprocessing for converting         
;*                 from external 4 bit format to our internal formats.                      
;*
;*                 Registers Preserved:         
;*                       BP,DS,ES               
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = ES:DI --> where color table is 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

eti_4   proc    near

        Mov     Cx,16                             ; create 16 color table entries
        Call    CreateColorTable

        Sub     Bx,Bx

        Mov     SrcScanLen.hi,Bx                 ; src scan never > 64k bytes
        Mov     Ax,ScanPixels                     ; # pixels in a src scan
        Add     Ax,7                              ; round up to dword boundary
        And     Al,Not 7                          ; lo order bits are extraneous
        Shr     Ax,1                              ; now # bytes
        Mov     SrcScanLen.lo,Ax                 ; stuff src scan length in bytes

        Test    fbsd,SD_COLOR                     ; a color destination ?
        Jnz     eti_4_color                       ; yes...

;/*
;** External 4 bpp to internal mono.
;*/

        Call    MungeColorTable_41               ; alter color table for this operation
        Mov     Dx,BitmapOFFSET CopyE4I1  ; -> 4:1 specialist

        Jmp     Short eti_4_have_proc

;/*
;** External 4 bpp to internal color bitmap. We have a choice internally of
;** going to a 4 or an 8 bit destination based on load-time configuration
;** parameters.
;*/

eti_4_color:

        Mov     Bx,ScanPixels                     ; # pixels in src scan
        Add     Bx,3                              ; round up to full word
        And     Bl,Not 3                          ; lo order bits are extraneous
        Shr     Bx,1                              ; now # full bytes in src
        Neg     Bx                                ; # bytes needed to pad to dword
        And     Bx,00000011b                      ; in lo 2 bits

        Mov     Dx,BitmapOFFSET CopyE4I8  ; assume -> 4:8 specialist

eti_4_have_proc:

        Mov     BufferAdjust,Bx                   ; add to src -> after xlate operation
        Mov     EtiProc,Dx                        ; store -> do'er routine

        Ret

eti_4   Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE eti_8
;*
;* DESCRIPTION   = Bitmap conversion, external 8 bit to internal format                     
;*                                                                                          
;*                 This routine is responsible for all preprocessing for converting         
;*                 from external 8 bit format to our internal formats                       
;*
;*                 Registers Preserved:         
;*                       BP,DS,ES               
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = ES:DI --> where color table is 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

eti_8   Proc    Near

        Mov     Cx,256                            ; create 256 color table entries
        Call    CreateColorTable

        Sub     Bx,Bx                             ; a zero

        Mov     SrcScanLen.hi,Bx                 ; src scan never > 64k bytes
        Mov     Ax,ScanPixels                     ; # pixels in a src scan
        Add     Ax,3                              ; round up to dword boundary
        And     Al,Not 3                          ; lo order bits are extraneous
        Mov     SrcScanLen.lo,Ax                 ; stuff src scan length in bytes

        Mov     Dx,BitmapOFFSET CopyE8I1  ; assume -> 8:1 specialist

        Test    fbsd,SD_COLOR                     ; a color destination ?
        Jz      eti_8_have_proc                   ; no, assumption correct...

;/*
;** External 8 bpp to internal color bitmap. We have a choice internally of
;** going to a 4 or an 8 bit destination based on load-time configuration
;** parameters.
;*/

        Mov     Dx,BitmapOFFSET CopyE8I8  ; load -> 8:8 specialist

eti_8_have_proc:

        Mov     BufferAdjust,Bx                   ; add to src -> after xlate operation
        Mov     EtiProc,Dx                        ; store -> do'er routine

        Ret

eti_8   endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE eti_24
;*
;* DESCRIPTION   = Bitmap conversion, external 24 bit RGB to internal format                
;*                                                                                          
;*                 This routine is responsible for all preprocessing for converting         
;*                 from external 24 bit RGB format to our internal formats                  
;*
;*                 Registers Preserved:         
;*                       BP,DS,ES               
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = ES:DI --> where color table is 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes Ds,nothing
        assumes Es,nothing

eti_24  Proc    Near

        Mov     Ax,ScanPixels                     ; pixels in a src scan
        Mov     Dx,3                              ; 3 bytes / RGB pixel
        Mul     Dx                                ; Dx:Ax is length in bytes of src

        Mov     Bx,Ax                             ; low word needed to get buffer adjust
        Neg     Bx
        And     Bx,00000011b                      ; # bytes to pad to dword boundary
        Mov     BufferAdjust,Bx

        Add     Ax,Bx                             ; Dx:Ax is now padded length of src
        Mov     SrcScanLen.lo,Ax
        Mov     SrcScanLen.hi,Dx                 ; stuff source scan length in bytes

        Mov     Dx,BitmapOFFSET CopyE24I8 ; assume -> 24:8 specialist

        Test    fbsd,SD_COLOR                     ; a color destination ?
        Jnz     eti_24_have_proc                 ; no, assumption correct...

        Mov     Dx,BitmapOFFSET CopyE24I1 ; assume -> 24:1 specialist
        or      fbPal,ETI_MONO

eti_24_have_proc:
        Mov     EtiProc,Dx                        ; store -> do'er routine

        Ret

eti_24  Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE get_color
;*
;* DESCRIPTION   = The color is converted from input to ipc. 
;*
;*                 Registers Preserved:         
;*                       BX,CX,SI,DI,BP,DS,ES   
;*                 Registers Destroyed:         
;*                       AX,DX                
;*
;* INPUT         = DX:AX = color data                       
;*                 SS:BP --> stack frame for bmc_ext_to_int 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AH:AL = ipc 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

        CPUMode 386
cProc   get_color,<NEAR,PUBLIC,NODATA>,<bx>
cBegin
        test    fbPal,ETI_PALETTE
        jnz     short gc_custom_palette
        cCall   far_rgb_to_ipc                    ; convert to internal physical color
        jmp     gc_got_ipc

gc_custom_palette:
        test    fbPal,ETI_PAL_INDICES
        jnz     short gc_pal_indices
        farPtr  myrgb,dx,ax
        cCall   far_rgb_to_ipc_with_pal,<myrgb,pPal>
        jmp     gc_got_ipc

gc_return_zero:
        xor     ax,ax
        cwd
        jmp     short gc_restore_stack

gc_pal_indices:
        push    ds                               ;!!! could speed up by doing this in outer
        push    si                               ;!!! routine and using GS instead of DS
        lds     si,pPal
        assumes ds,nothing
        ror     eax,16
        xchg    ax,dx
        ror     eax,16
        index?  gc_return_zero,ds,si,SIZE_HW_PAL-1
gc_restore_stack:
        pop     si
        pop     ds
        assumes ds,nothing

        test    fbPal,ETI_MONO
        jz      gc_got_ipc

;/*
;** Get the mono bit of the palette index.  The palette index is valid.
;*/

        push    ds
        lds     bx,pPal
        assumes ds,nothing
        palOff  ax
        add     bx,ax
        mov     dx,word ptr [bx].palseg_apalclr.palclr_rgb.rgb2_bRed
        mov     bx,word ptr [bx].palseg_apalclr.palclr_rgb.rgb2_bBlue
        pop     ds
        assumes ds,nothing

        test    dh,PC_EXPLICIT
        jz      gc_compute_mono_bit

;/*
;** It's a PC_EXPLICIT color, so go look up the color in the hardware.
;*/

        push    ds
        push    si
        mov     ds,BitmapData
        assumes ds,Data
ifdef FIREWALLS
        mov     si,ds
        assert  si,E,<phwpal.hi>
endif
        mov     si,phwpal.lo
        assumes ds,nothing
        movzx   bx,bl
        rgbOff  bx
        mov     dl,         [si+bx].rgb2_bRed
        mov     bx,word ptr [si+bx].rgb2_bBlue
        pop     si
        pop     ds
        assumes ds,nothing

;/*
;** Now that we have the RGB, compute the mono bit from it.
;**
;** DL:BX = R|G|B
;*/

gc_compute_mono_bit:
        xor     ah,ah
        add     bl,bh
        setc    bh
        add     bl,dl
        adc     bh,0
        cmp     bx,180h
        jb      short gc_got_ipc
        or      ah,HIGH MONO_BIT
        .errnz  LOW MONO_BIT
        .errnz  HIGH MONO_BIT - 00000001b

gc_got_ipc:
cEnd
        CPUMode 286

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE create_color_table
;*
;* DESCRIPTION   = The color table for translating from user colors to our colors           
;*                 is generated                                                             
;*
;*                 Registers Preserved:         
;*                       BP,DS,ES               
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,DI,FLAGS  
;*
;* INPUT         = ES:DI --> where color table is
;*                 CX    =   total number of color table entries
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes Ds,nothing
        assumes Es,nothing

CreateColorTable        Proc                     Near

        lea     bx,ColorXlate                     ; effective addr of xlate table
        mov     si,lpddc.lo                       ; needed for rgb_to_ipc

cct_loop:

;/*
;** fetch an RGB and convert to an IPC
;*/

        Mov     Ax,Es:[Di][0]                     ; fetch G|R
        Mov     Dl,Es:[Di][2]                     ; fetch B
        test    fbsd,SD_COLOR                     ; going to color bitmap ?
        jnz     color_bitmap

;/*
;** we are going to a mono bitmap so all that interests us is the
;** MONO_BIT value which we can calculate from the RGB data directly
;*/
        xor     dh,dh                             ; zero dh
        add     dl,ah                             ; sum red and green
        adc     dh,dh                             ; include any carry to the high byte
                                                  ; (dh was zero from above)
        xor     ah,ah                             ; make ax just contain blue
        add     dx,ax                             ; add blue to the total
        xor     al,al                             ; prepare al to take MONO_BIT
        cmp     dx,384                            ; set carry if sum < 384
        cmc                                       ; set carry if sum >= 384
        adc     al,al                             ; set MONO_BIT if sum >= 384
        .errnz  MONO_BIT-100h
        jmp     short store_entry
color_bitmap:
        Call    far_rgb_to_ipc                    ; convert to internal physical color

store_entry:
        mov     ss:[bx],al                        ; store into local color xlate table
        inc     bx                                ; point at next color xlate table entry
        Add     Di,rgb_size                       ;int at next RGB

        Loop    cct_loop                          ; for all table entries to create...

        Ret
CreateColorTable        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE MungeColorTable_41
;*
;* DESCRIPTION   = The already created 4 bit color translate table is munged to             
;*                 facilitate the conversion from external 4 bit format to                  
;*                 internal 1 bit format.  The 16 table entries are replicated 15           
;*                 additional times to yield a total of 256 entries.  Each entry            
;*                 contains the MONO_BIT for the leftmost pixel of a pair in the            
;*                 hi bit and the MONO_BIT for the rightmost pixel of a source              
;*                 pair in the next to hi bit of the entry.  This encoding allows           
;*                 us to translate two source pixels at a time.  At the start,              
;*                 the table has the MONO_BIT in the least significant bit of the           
;*                 first 16 bytes, so we must handle the first row differently              
;*                 from the other 15.                                                       
;*
;*                 Registers Preserved:         
;*                       BX,BP,DS,ES
;*                 Registers Destroyed:         
;*                       AX,CX,DX,DI,FLAGS  
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,Data
        assumes Es,nothing

MungeColorTable_41      Proc                     Near
        Push    Ds
        Push    Bx

        Lea     Bx,ColorXlate
        mov     di,bx
        Mov     Ax,Ss
        Mov     Ds,Ax
        assumes Ds,nothing                        ; Ds:Bx -> color xlate table
        Mov     Es,Ax
        assumes Es,nothing                        ; Es:Di -> color xlate table

        mov     ah,[bx]
        and     ah,high MONO_BIT
        .errnz  High MONO_BIT - 00000001b
        ror     ah,1

        mov     cx,16
        mov     si,bx
mct_41_first_row:
        lodsb
        and     al,high MONO_BIT
        .errnz  High MONO_BIT - 00000001b
        ror     al,2
        or      al,ah
        stosb
        loop    mct_41_first_row

        mov     dx,15
mct_41_outer:
        inc     bx
        mov     ah,[bx]
        shl     ah,1
        mov     cx,16
        lea     si,ColorXlate
mct_41_inner:
        lodsb
        and     al,(high MONO_BIT) shl 6
        .errnz  ((high MONO_BIT) shl 6) - 01000000b
        or      al,ah
        stosb
        loop    mct_41_inner
        dec     dx
        jnz     mct_41_outer

        Pop     Bx
        Pop     Ds
        assumes Ds,Data
        Ret
MungeColorTable_41      Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE GetNextDsSelector
;*
;* DESCRIPTION   = The next destination selector (if it exists) will be loaded.
;*
;*                 Registers Preserved:     
;*                       Ax,Bx,Cx,Dx,Si,Di,Bp,Es 
;*                 Registers Destroyed:          
;*                       FLAGS                   
;*
;* INPUT         = DS --> current src selector      
;* OUTPUT        = DS --> new src selector if next one exists and is valid 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C' = 0 if next selector is gotten                   
;*                 'C' = 1 if next selector doesn't exist or is invalid 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

        Public  GetNextDsSelector
GetNextDsSelector       Proc Near

        Push    Ax
        Push    Dx

        Mov     Dx,Ds
        Add     Dx,DOSHUGEINCR

        Lar     Ax,Dx                             ; is user segment accessible ?
        stc                                       ; in case failed
        Jnz     @F                                ; don't load new Ds if failed
        Mov     Ds,Dx                             ; user segment is safe to access
        assumes Ds,nothing
        clc                                       ; show no error
@@:

        Pop     Dx
        Pop     Ax

        Ret

GetNextDsSelector Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I1_0s
;*
;* DESCRIPTION   = 0s are copied into the internal mono bitmap. 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I1_0s     Proc    Near
        Sub     Ax,Ax
        Jmp     CopyE1I1_0s_1s
CopyE1I1_0s     Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I1_1s
;*
;* DESCRIPTION   = 1s are copied into the internal mono bitmap.
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I1_1s     Proc    Near
        Mov     Ax,0ffffh
        errn$   CopyE1I1_0s_1s
CopyE1I1_1s     Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I1_0s_1s
;*
;* DESCRIPTION   = 1s or 0s are copied into the internal mono bitmap.
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I1_0s_1s  Proc    Near

        Add     Cx,31                             ; round up to dword boundary
        And     Cl,Not 31                         ; getting rid of lo order bits

        Shr     Cx,4                              ; 16 pixels/word = # words to xfer
        Mov     Dx,Cx                             ; save
    Rep Stosw                                     ; transfer whole words

        Shl     Dx,1                              ; # bytes we just xfer'ed
        Add     Si,Dx                             ; update src pointer
        Jnc     @F                                ; no need to get next selector
        Call    GetNextDsSelector                ; advance to next segment
@@:                                               ; error flag now set 0 or 1

        Ret                                       ; success return, 'C' has error flag
CopyE1I1_0s_1s  Endp
 
page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I1
;*
;* DESCRIPTION   = Source mono pixels are copied into the internal mono bitmap. 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I1        Proc    Near

        Jc      CE1I1_Slow                        ; have to handle segment crossings...

;/*
;** The source scan does not span two segments
;*/

        Add     Cx,31                             ; round up to dword boundary
        And     Cl,Not 31                         ; getting rid of lo order bits

        Shr     Cx,4                              ; 16 pixels/word = # words to xfer
    Rep Movsw                                     ; transfer whole words

        Ret                                       ; success return, 'C'=0 from Shr above

CE1I1_Slow:

;/*
;** The source scan will cross segments. We must check for and handle the
;** crossing.
;*/

        Add     Cx,31                             ; round up to dword boundary
        And     Cl,Not 31                         ; lo order bits are extraneous

        Shr     Cx,3                              ; 8 pixels / byte = # full bytes to xfer
        Mov     Dx,Cx                             ; keep total byte count (always even)

        Mov     Cx,Si                             ; get # bytes to xfer in this seg
        Neg     Cx                                ; Cx = # bytes to do in this seg
        Sub     Dx,Cx                             ; Dx = # bytes to do in next seg

        Shr     Cx,1                              ; # whole words
    Rep Movsw                                     ; transfer whole words
        Rcl     Cx,1                              ; process any trailing byte
    Rep Movsb

        Call    GetNextDsSelector                ; try to get next selector
        Jc      CE1I1_Slow_Exit                   ; return with an error, 'C' set


        Ror     Di,1                              ; check possible odd byte at front
        Rcl     Cx,1
        Rol     Di,1
        Sub     Dx,Cx                             ; update count if writing byte
    Rep Movsb
        Mov     Cx,Dx                             ; # bytes to xfer in new seg
        Shr     Cx,1                              ; # full words to xfer
    Rep Movsw                                     ; move full words
        Rcl     Cx,1                              ; process possible trailing byte
    Rep Movsb

                                                  ; no errors, 'C'=0 from Rcl above

CE1I1_Slow_Exit:

        Ret
CopyE1I1        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I1_Invert
;*
;* DESCRIPTION   = Inverted source mono pixels are copied into 
;*                 the internal mono bitmap.
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I1_Invert Proc    Near

        Jc      CE1I1_Invert_Slow                ; have to handle segment crossings...

;/*
;** The source scan does not span two segments
;*/

        Add     Cx,31                             ; round up to dword boundary
        And     Cl,Not 31                         ; lo order bits are extraneous
        Shr     Cx,4                              ; # whole words to move

@@:     Lodsw                                     ; fetch source word
        Not     Ax                                ; invert, don't affect flags
        Stosw                                     ; store to destination
        Loop    @B                                ; for all words to xfer...

        Ret                                       ; success return, 'C'=0 from Shr above

CE1I1_Invert_Slow:

;/*
;** The source scan will cross segments. We must check for and handle the
;** crossing.
;*/

        Add     Cx,31                             ; round up to dword boundary
        And     Cl,Not 31                         ; lo order bits are extraneous

        Shr     Cx,3                              ; 8 pixels / byte = # full bytes to xfer
        Mov     Dx,Cx                             ; keep total byte count
        Mov     Cx,Si                             ; get # bytes to xfer in this seg
        Neg     Cx                                ; Cx = # bytes to do in this seg
        Sub     Dx,Cx                             ; Dx = # bytes to do in next seg

        Shr     Cx,1                              ; # whole words
        Jcxz    @F                                ; no whole words...
CE1I1_Invert_Slow_0:                              ; no flags affected in this loop
        Lodsw                                     ; fetch a src word
        Not     Ax                                ; invert (does not affect flags)
        Stosw                                     ; store to dest
        Loop    CE1I1_Invert_Slow_0
@@:

        Jnc     @F                                ; no trailing byte...
        Lodsb                                     ; fetch a src byte
        Not     Al                                ; invert
        Stosb                                     ; store to dest
@@:

        Call    GetNextDsSelector                ; try to get next selector
        Jc      CE1I1_Invert_Slow_Exit           ; return with an error, 'C' set

        Mov     Cx,Dx                             ; # bytes to xfer in new seg
        Shr     Cx,1                              ; # full words to xfer
        Jcxz    @F                                ; no whole words...
CE1I1_Invert_Slow_1:                              ; no flags affected in this loop
        Lodsw                                     ; fetch a src word
        Not     Ax                                ; invert (does not affect flags)
        Stosw                                     ; store to dest
        Loop    CE1I1_Invert_Slow_1
@@:

        Jnc     @F                                ; no trailing byte...
        Lodsb                                     ; fetch a src byte
        Not     Al                                ; invert
        Stosb                                     ; store to dest
        Clc                                       ; reset carry to return success
@@:

CE1I1_Invert_Slow_Exit:

        Ret
CopyE1I1_Invert Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE1I8                                                       
;*                                                                                
;* DESCRIPTION   = External mono pixels are copied into the internal 8 bpp bitmap 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE1I8        Proc    Near

        Mov     Bx,Word Ptr ColorXlate           ; load index 0,1 IPCs
        Mov     Dx,Cx                             ; keep src pixel count here

CE1I8_lp0:
        Mov     Cx,8                              ; will write 8 destination pixels
        Cmp     Cx,Dx
        Jb      @F                                ; @ least 8 pixels to write...
        Mov     Cx,Dx                             ; was < 8 pixels left
@@:     Sub     Dx,Cx                             ; account for pixels about to write

        Lodsb                                     ; fetch next source byte
        Mov     Ch,Al                             ; free up Al

CE1I8_lp1:
        Shl     Ch,1                              ; next mono bit to lo bit Al
        Sbb     Ax,Ax                             ; mono pixel replicated
        Not     Al                                ; inverted,replicated also
        And     Ax,Bx                             ; get colors
        Or      Al,Ah                             ; to Al
        Stosb                                     ; store into destination
        Dec     Cl
        Jnz     CE1I8_lp1                         ; for all pixels in the source byte...

        Or      Si,Si                             ; will next byte fetch ovf seg ?
        Jz      CE1I8_NextSeg                     ; yes -- take care of it now...

CE1I8_Reentry:

        Or      Dx,Dx                             ; all done ?, reset 'C' too
        Jnz     CE1I8_lp0                         ; no...

        Ret                                       ; success return, 'C' reset


CE1I8_NextSeg:

;/*
;** handle (outside of the loop) ovf into the next segment
;*/

        Call    GetNextDsSelector                ; try to get next selector
        Jnc     CE1I8_Reentry                     ; if successful reenter loop
        Ret                                       ; else return with an error, 'C' set
        
CopyE1I8        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE4I1                                                       
;*                                                                                
;* DESCRIPTION   = External 4 bpp pixels are copied into the internal mono bitmap 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE4I1        Proc    Near

;/*
;** We point to our munged version of the color translate table for 4 to 1
;** translation. Here the color table has been filled with 16 sets of 16
;** colors such that the translated color for the left pixel of a source byte
;** is contained in bit 7 of each entry of the color table, and the translated
;** color for the right pixel of a source byte is contained in bit 6 of each
;** entry of the color table. This allows us to translate two source pixels with
;** one Xlat instruction in the inner loop.
;*/

        Lea     Bx,ColorXlate                     ; -> color translation table

        Jc      CE4I1_Slow                        ; source will cross segment boundary...

;/*
;** Because the source is dword padded we are safe in translating 8 source
;** pixels at a time (yielding 1 full dest byte).
;*/

        Add     Cx,7                              ; always xlate full dwords from src
        Shr     Cx,3                              ; now # dwords in source

CE4I1_lp0:

        Lodsw                                     ; fetch 4 source pixels
        Xlat    Ss:[Bx]                           ; xlate first two into 2 dest pixels
        Mov     Dl,Al
        Shl     Dx,2                              ; shift up into building dest byte
        Mov     Al,Ah                             ; get next 2 src pixels
        Xlat    Ss:[Bx]                           ; xlate into 2 dest pixels
        Mov     Dl,Al
        Shl     Dx,2                              ; shift up into building dest byte

        Lodsw                                     ; fetch 2 source pixels
        Xlat    Ss:[Bx]                           ; xlate into 2 dest pixels
        Mov     Dl,Al
        Shl     Dx,2                              ; shift up into building dest byte
        Mov     Al,Ah
        Xlat    Ss:[Bx]                           ; xlate into 2 dest pixels
        Mov     Dl,Al
        Shl     Dx,2                              ; shift up into building dest byte

        Mov     Al,Dh                             ; get composed dest byte
        Stosb                                     ; store full destination byte

        Loop    CE4I1_lp0                         ; more to do...

        clc                                       ; success return, 'C' reset
        ret


;/*
;** The source scan crosses a segment boundary.
;*/

CE4I1_Slow:

;/*
;** Because the source is dword padded we are safe in translating 8 source
;** pixels at a time (yielding 1 full dest byte).
;*/

        Add     Cx,7                              ; always xlate full dwords from src
        Shr     Cx,3                              ; now # dwords in source

CE4I1_Slow_lp0:

        Mov     Dl,4                              ; loop for 4 src bytes

CE4I1_Slow_lp1:

        Lodsb                                     ; fetch 2 source pixels
        Xlat    Ss:[Bx]                           ; xlate into 2 dest pixels
        Shl     Ax,2                              ; shift up into building dest byte

        Or      Si,Si                             ; ovf into next source seg ?
        Jnz     @F                                ; not yet...
        Call    GetNextDsSelector                ; advance to next segment
        Jc      CE4I1_Slow_Exit                   ; we blew it!
@@:

        Dec     Dl                                ; drop # src bytes to build 1 dest byte
        Jnz     CE4I1_Slow_lp1                    ; continue building dest byte...

        Mov     Al,Ah                             ; get composed dest byte
        Stosb                                     ; store full destination byte

        Loop    CE4I1_lp0                         ; more to do...

CE4I1_Slow_Exit:

        Ret                                       ; return, 'C' set if error
CopyE4I1        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE4I8                                                       
;*                                                                                
;* DESCRIPTION   = External 4 bpp pixels are copied into the internal 8 bpp bitmap 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE4I8        Proc    Near

        Lea     Bx,ColorXlate                     ; -> color translation table

        Jc      CE4I8_Slow                        ; src crosses a segment boundary...

        Add     Cx,3                              ; round up to source words
        Shr     Cx,2                              ; 4 src pixels / word = src words

CE4I8_lp0:

        Lodsw                                     ; fetch four source pixels
        Mov     Dh,Ah                             ; save rightmost two

        Mov     Ah,Al                             ; clone leftmost two
        And     Al,00fh                           ; zext right pixel
        Xlat    Ss:[Bx]                           ; get IPC for right pixel
        Xchg    Ah,Al                             ; leftmost pixel to Al
        Shr     Al,4                              ; left pixel to lo nibble, zext'ed
        Xlat    Ss:[Bx]                           ; get IPC for left pixel
        Stosw                                     ; store into destination

        Mov     Al,Dh                             ; fetch rightmost pixels
        Mov     Ah,Al                             ; clone the pixels
        And     Al,00fh                           ; zext right pixel
        Xlat    Ss:[Bx]                           ; get IPC for right pixel
        Xchg    Ah,Al                             ; leftmost pixel to Al
        Shr     Al,4                              ; left pixel to lo nibble, zext'ed
        Xlat    Ss:[Bx]                           ; get IPC for left pixel
        Stosw                                     ; store into destination

        Loop    CE4I8_lp0                         ; more to fetch...

        clc                                       ; success return, 'C' reset
        ret


;/*
;** The source scan will cross a segment boundary.
;*/

CE4I8_Slow:

        Add     Cx,3                              ; round up to source words
        And     Cl,Not 3                          ; lo order bits are extraneous
        Shr     Cx,1                              ; # source bytes to fetch

CE4I8_Slow_lp0:

        Lodsb                                     ; fetch 2 source pixels
        Mov     Ah,Al                             ; clone them
        And     Al,00fh                           ; right pixel masked in lo nibble
        Xlat    Ss:[Bx]                           ; get destination IPC
        Xchg    Ah,Al                             ; left pixel fetched
        Shr     Al,4                              ; left pixel to lo nibble
        Xlat    Ss:[Bx]                           ; get destination IPC
        Stosw                                     ; store 2 dest pixels

        Or      Si,Si                             ; ovf into next source segment ?
        Jnz     @F                                ; not yet...
        Call    GetNextDsSelector                ; advance to next segment
        Jc      CE4I8_Slow_Exit                   ; it failed...
@@:

        Loop    CE4I8_Slow_lp0                    ; more src pixels to fetch...

CE4I8_Slow_Exit:

        Ret                                       ; else return with an error, 'C' set

CopyE4I8        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE8I1                                                       
;*                                                                                
;* DESCRIPTION   = External 8 bpp pixels are copied into the internal mono bitmap
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE8I1        Proc    Near

        Lea     Bx,ColorXlate                     ; -> color translation table

        Jc      CE8I1_Slow                        ; source crosses a segment boundary...

        Add     Cx,3                              ; always xlate full dwords from src
        Shr     Cx,2                              ; now # dwords in source

        Mov     Dl,01010101b                      ; bit pattern tells us when to write
                                                  ; a destination byte

CE8I1_lp0:

        Lodsw                                     ; fetch two source pixels
        Xlat    Ss:[Bx]                           ; xlate into a dest pixel
        Shr     Al,1                              ; MONO_BIT to carry
        Rcl     Dh,1                              ; add to building dest byte
        Mov     Al,Ah
        Xlat    Ss:[Bx]                           ; xlate into a dest pixel
        Shr     Al,1                              ; MONO_BIT to carry
        Rcl     Dh,1                              ; add to building dest byte

        Lodsw                                     ; fetch a source pixel
        Xlat    Ss:[Bx]                           ; xlate into a dest pixel
        Shr     Al,1                              ; MONO_BIT to carry
        Rcl     Dh,1                              ; add to building dest byte
        Mov     Al,Ah
        Xlat    Ss:[Bx]                           ; xlate into a dest pixel
        Shr     Al,1                              ; MONO_BIT to carry
        Rcl     Dh,1                              ; add to building dest byte

        Rol     Dl,1                              ; full dest byte built up ?
        Jnc     @F                                ; not yet...
        Mov     Al,Dh
        Stosb                                     ; store full destination byte
@@:

        Loop    CE8I1_lp0                         ; for all source pixels...

        Rol     Dl,1                              ; a partial last byte ?
        jnc     @F                                ; no...
        mov     al,dh
        Shl     Al,4                              ; yes, normalize the partial byte
        Stosb                                     ; store partial dest byte
@@:
        Clc                                       ; never crossed a seg bdry so no error
        Ret                                       ; success return, 'C' reset


;/*
;** The source scan will cross a segment boundary.
;*/

CE8I1_Slow:

        Add     Cx,3                              ; round src up to dword boundary
        And     Cl,Not 3                          ; now # bytes to xfer

        Mov     Dl,00000001b                      ; tells us when to write dest byte

CE8I1_Slow_lp0:

        Lodsb                                     ; fetch a src pixel
        Xlat    Ss:[Bx]                           ; translate colors
        Shr     Al,1
        Rcl     Dh,1                              ; add to building dest byte

        Rol     Dl,1                              ; full dest byte composed yet ?
        Jnc     @F                                ; no...
        Mov     Al,Dh
        Stosb                                     ; yes, write full byte to dest
@@:

        Or      Si,Si                             ; ovf to next segment ?
        Jnz     @F                                ; no...
        Call    GetNextDsSelector                ; advance to next segment
        Jc      CE8I1_Slow_Done                   ; it failed...
@@:

        Loop    CE8I1_Slow_lp0                    ; for all source pixels...

CE8I1_Slow_Done:

        Pushf                                     ; save error indicator
        Test    Dl,00000001b                      ; a partial last byte ?
        Jnz     @F                                ; no...
CE8I1_Slow_lp1:
        Shl     Dh,1                              ; left align dest byte
        Rol     Dl,1                              ; until up to left side
        Jnc     CE8I1_Slow_lp1
        Mov     Al,Dh                             ; fetch partial last byte
        Stosb                                     ; store it to destination
@@:     Popf                                      ; recover error flag

        Ret                                       ; return with error flag

CopyE8I1        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE8I8
;*                                                                                
;* DESCRIPTION   = External 8 bpp pixels are copied into the internal 8 bpp bitmap 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE8I8        Proc    Near

        Lea     Bx,ColorXlate                     ; -> color translation table

        Jc      CE8I8_Slow                        ; source crosses segment boundary...

        Add     Cx,3                              ; round up to dword boundary
        Shr     Cx,2                              ; # source dwords to xfer

CE8I8_lp0:

        Lodsw                                     ; fetch two source pixels
        Xlat    Ss:[Bx]                           ; get IPC for left pixel
        Xchg    Ah,Al                             ; save left, get right
        Xlat    Ss:[Bx]                           ; get IPC for right pixel
        Xchg    Ah,Al                             ; swap back to correct left,right order
        Stosw                                     ; store into destination

        Lodsw                                     ; fetch two source pixels
        Xlat    Ss:[Bx]                           ; get IPC for left pixel
        Xchg    Ah,Al                             ; save left, get right
        Xlat    Ss:[Bx]                           ; get IPC for right pixel
        Xchg    Ah,Al                             ; swap back to correct left,right order
        Stosw                                     ; store into destination

        Loop    CE8I8_lp0                         ; more to fetch...

        clc                                       ; success return, 'C' reset
        ret


;/*
;** The source scan will cross a segment boundary.
;*/

CE8I8_Slow:

        Add     Cx,3                              ; round src up to dword boundary
        And     Cl,Not 3                          ; # bytes of src to translate

CE8I8_Slow_lp0:

        Lodsb                                     ; fetch a src pixel
        Xlat    Ss:[Bx]                           ; translate colors
        Stosb                                     ; store to destination

        Or      Si,Si                             ; src ovf into next segment ?
        Jnz     @F                                ; no...
        Call    GetNextDsSelector                ; advance to next segment
        Jc      CE8I8_Slow_Exit                   ; it failed...
@@:

        Loop    CE8I8_Slow_lp0                    ; for all source pixels...

CE8I8_Slow_Exit:

        Ret

CopyE8I8        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE24I1
;*                                                                                
;* DESCRIPTION   = External RGB pixels are copied into the internal mono bitmap 
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*                       far_rgb_to_ipc
;*                       ifdef PALMGR
;*                             get_color
;*                       endif
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyE24I1       Proc    Near

        Mov     Bh,00000001b                      ; 8 src pixels to 1 dest byte

        Jc      CE24I1_Slow                       ; source crosses segment boundary...

CE24I1_lp0:

        Lodsw                                     ; fetch R,G
        Mov     Dl,Al
        Lodsb                                     ; fetch B
        Xchg    Al,Dl                             ; components to correct registers

ifdef PALMGR
        cCall   get_color
else
        Call    far_rgb_to_ipc                        ; get internal colors
endif

        Shr     Ah,1                              ; get mono bit to carry
        Rcl     Bl,1                              ; add to building dest byte

        Rol     Bh,1                              ; full dest byte yet ?
        Jnc     @F                                ; no...
        Mov     Al,Bl
        Stosb                                     ; yes, store to dest
@@:

        Loop    CE24I1_lp0                        ; for all source pixels...

        Test    Bh,00000001b                      ; partial last byte ?
        Jnz     @F                                ; no...
CE24I1_lp1:
        Shl     Bl,1                              ; shift to left end of byte
        Rol     Bh,1
        Jnc     CE24I1_lp1
        Mov     Al,Bl
        Stosb                                     ; store normalized dest byte
@@:

        Clc
        Ret                                       ; success return


;/*
;** The source scan will cross a segment boundary.
;*/

CE24I1_Slow:

CE24I1_Slow_lp0:

        Lodsb                                     ; fetch R
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I1_NextSeg_0                 ; yes...
CE24I1_Reenter_0:
        Mov     Dl,Al                             ; save R

        Lodsb                                     ; fetch G
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I1_NextSeg_1                 ; yes...
CE24I1_Reenter_1:
        Mov     Ah,Al

        Lodsb                                     ; fetch B
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I1_NextSeg_2                 ; yes...
CE24I1_Reenter_2:
        Xchg    Al,Dl

ifdef PALMGR
        cCall   get_color
else
        Call    far_rgb_to_ipc                        ; get internal colors
endif

        Shr     Ah,1                              ; get mono bit to carry
        Rcl     Bl,1                              ; add to building dest byte

        Rol     Bh,1                              ; full dest byte yet ?
        Jnc     @F                                ; no...
        Mov     Al,Bl
        Stosb                                     ; yes, store to dest
@@:

        Loop    CE24I1_Slow_lp0                   ; for all source pixels...

        Clc                                       ; if we fall out here, no errors

CE24I1_Slow_Done:
        Pushf                                     ; save error return
        Test    Bh,00000001b                      ; partial last byte ?
        Jnz     @F                                ; no...
CE24I1_Slow_lp1:
        Shl     Bl,1                              ; shift to left end of byte
        Rol     Bh,1
        Jnc     CE24I1_Slow_lp1
        Mov     Al,Bl
        Stosb                                     ; store normalized dest byte
@@:     Popf                                      ; recover error flag

        Ret


CE24I1_NextSeg_0:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I1_Reenter_0                 ; we did...
        Ret                                       ; we didn't

CE24I1_NextSeg_1:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I1_Reenter_1                 ; we did...
        Ret                                       ; we didn't

CE24I1_NextSeg_2:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I1_Reenter_2                 ; we did...
        Jmp     CE24I1_Slow_Done                 ; purge possible last dest byte...

CopyE24I1       Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyE24I8
;*                                                                                
;* DESCRIPTION   = External RGB pixels are copied into the internal 8 bpp bitmap
;*
;*                 Registers Preserved:     
;*                       Bx,Bp,Ds,Es        
;*                 Registers Destroyed:     
;*                       Ax,Cx,Dx,Si,Di     
;*                 Calls:
;*                       GetNextDsSelector
;*                       far_rgb_to_ipc
;*                       ifdef PALMGR
;*                             get_color
;*                       endif
;*
;* INPUT         = [Cx]    =       # source pixels to xfer                        
;*                 [Ds:Si] =       -> start of source scan                        
;*                 [Es:Di] =       -> start of destination scan                   
;*                 'C'     =       0 if there will be no ovf across src segments 
;*                 'C'     =       1 if the src scan crosses two user segment    
;*
;* OUTPUT        = [Ds:Si] =       -> next source scan less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector 
;**************************************************************************/
 
        assumes Ds,nothing
        assumes Es,nothing

CopyE24I8       Proc    Near

        Jc      CE24I8_Slow                       ; source crosses segment boundary...

CE24I8_lp0:

        Lodsw                                     ; fetch R,G
        Mov     Dl,Al
        Lodsb                                     ; fetch B
        Xchg    Al,Dl                             ; components to correct registers
ifdef PALMGR
        cCall   get_color
else
        Call    far_rgb_to_ipc                        ; get internal colors
endif
        Stosb                                     ; store to dest

        Loop    CE24I8_lp0                        ; for all source pixels...

        Clc
        Ret                                       ; success return


;/*
;** The source scan will cross a segment boundary.
;*/

CE24I8_Slow:

CE24I8_Slow_lp0:

        Lodsb                                     ; fetch R
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I8_NextSeg_0                 ; yes...
CE24I8_Reenter_0:
        Mov     Dl,Al                             ; save R

        Lodsb                                     ; fetch G
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I8_NextSeg_1                 ; yes...
CE24I8_Reenter_1:
        Mov     Ah,Al

        Lodsb                                     ; fetch B
        Or      Si,Si                             ; ovf into next segment ?
        Jz      CE24I8_NextSeg_2                 ; yes...
CE24I8_Reenter_2:
        Xchg    Al,Dl

ifdef PALMGR
        cCall   get_color
else
        Call    far_rgb_to_ipc                        ; get internal colors
endif
        Stosb                                     ; yes, store to dest

        Loop    CE24I8_Slow_lp0                   ; for all source pixels...

        Clc                                       ; if we fall out here, no errors
        Ret


CE24I8_NextSeg_0:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I8_Reenter_0                 ; we did...
        Ret                                       ; we didn't

CE24I8_NextSeg_1:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I8_Reenter_1                 ; we did...
        Ret                                       ; we didn't

CE24I8_NextSeg_2:
        Call    GetNextDsSelector                ; advance to next segment
        Jnc     CE24I8_Reenter_2                 ; we did...
        Ret                                       ; we didn't
        
CopyE24I8       Endp

sEnd    Bitmap


ifdef   FIREWALLS
        public  eti_not_a_bitmap
        public  eti_its_a_Bitmap
endif
        public  eti_log_error
        public  eti_get_out
        public  eti_xfered_all_relay
        public  eti_numbers_ok
ifdef FIREWALLS
        public  eti_cbi_failed
endif
        public  eti_isnt_huge_bitmap
        public  eti_huge_bitmap
        public  eti_finish_y_calc
        public  eti_next_scan
        public  eti_in_segment
        public  eti_might_cross_seg
        public  eti_xfered_all
        public  eti_exit
        public  eti_1_color
        public  eti_1_have_proc
        public  eti_4_color
        public  eti_4_have_proc
        public  eti_8_have_proc
        public  eti_24_have_proc
        public  cct_loop
        public  CE1I1_Slow
        public  CE1I1_Slow_Exit
        public  CE1I1_Invert_Slow
        public  CE1I1_Invert_Slow_0
        public  CE1I1_Invert_Slow_1
        public  CE1I1_Invert_Slow_Exit
        public  CE1I8_lp0
        public  CE1I8_lp1
        public  CE1I8_Reentry
        public  CE1I8_NextSeg
        public  CE4I1_lp0
        public  CE4I1_Slow
        public  CE4I1_Slow_lp0
        public  CE4I1_Slow_lp1
        public  CE4I1_Slow_Exit
        public  CE4I8_lp0
        public  CE4I8_Slow
        public  CE4I8_Slow_lp0
        public  CE4I8_Slow_Exit
        public  CE8I1_lp0
        public  CE8I1_Slow
        public  CE8I1_Slow_lp0
        public  CE8I1_Slow_Done
        public  CE8I1_Slow_lp1
        public  CE8I8_lp0
        public  CE8I8_Slow
        public  CE8I8_Slow_lp0
        public  CE8I8_Slow_Exit
        public  CE24I1_lp0
        public  CE24I1_lp1
        public  CE24I1_Slow
        public  CE24I1_Slow_lp0
        public  CE24I1_Reenter_0
        public  CE24I1_Reenter_1
        public  CE24I1_Reenter_2
        public  CE24I1_Slow_Done
        public  CE24I1_Slow_lp1
        public  CE24I1_NextSeg_0
        public  CE24I1_NextSeg_1
        public  CE24I1_NextSeg_2
        public  CE24I8_lp0
        public  CE24I8_Slow
        public  CE24I8_Slow_lp0
        public  CE24I8_Reenter_0
        public  CE24I8_Reenter_1
        public  CE24I8_Reenter_2
        public  CE24I8_NextSeg_0
        public  CE24I8_NextSeg_1
        public  CE24I8_NextSeg_2


        public  CreateColorTable
        public  MungeColorTable_41
        public  GetNextDsSelector
        public  CopyE1I1_0s
        public  CopyE1I1_1s
        public  CopyE1I1_0s_1s
        public  CopyE1I1
        public  CopyE1I1_Invert
        public  CopyE1I8
        public  CopyE4I1
        public  CopyE4I8
        public  CopyE8I1
        public  CopyE8I8
        public  CopyE24I1
        public  CopyE24I8

        End
