;*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_ITE.ASM
;*
;* DESCRIPTIVE NAME = Bitmap Conversion - Internal to External
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/16/87
;*
;* DESCRIPTION  
;*              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_int_to_ext
;*              
;*
;* 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/16/87                     Author:  Geoff Shapiro [gssc!geoffs]
;*   11/09/87                     Bob Grudem [bobgru] Internal color bitmaps 
;*                                always use interleaved (i.e. huge)
;*                                scanline format.
;*   05/01/90                     Viroon Touranachun [viroont] Add the inquiry 
;*                                option, i.e., pBuf = NULL, for requesting just
;*                                the extracted size.
;       Tue 01-May-1990 14:25:17 -by-  Viroon Touranachun [viroont]
;       Add the inquiry option, i.e., pBuf = NULL, for requesting just
;       the extracted size.
;
;       Mon 09-Nov-1987 14:29:00 -by-  Bob Grudem [bobgru]
;       Internal color bitmaps always use interleaved (i.e. huge)
;       scanline format.
;  Thu 13-Oct-1988 11:02:53 -by-  Lee A. Newberg [leen]
; Fixed the processing of the last byte output.
;  Wed 12-Oct-1988 20:55:59 -by-  Lee A. Newberg [leen]
; Divides input CX in half to get number of bytes to output.
;  Thu 27-Jul-1989 11:04:22 -by-  Wesley O. Rupel [wesleyr]
; Fixed conversion problem.
;
;  Wed 12-Oct-1988 21:05:38 -by-  Lee A. Newberg [leen]
; Fixed special gray.
;*
;*****************************************************************************/

        CPUMode 286
        .xlist
        include cmacros.inc
INCL_GRE_BITMAPS        equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPILOGCOLORTABLE   equ     1
        include pmgre.inc
DINCL_BITMAP            equ     1
DINCL_CLR_TBL           equ     1
        include driver.inc
        include display.inc
        include njmp.mac
        include assert.mac
        include bmi2.inc
        include palette.inc
        .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              ; -> bitmap info for color bitmap
        externB ctDefault
        externB palsegDefPal
        externB PalColor16
        externB aIPC256toIPC16
sEnd    Data

        externFP far_check_bitmap_info
        externFP MatchTwoPalettes
        externFP far_rgb_to_ipc_with_pal

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      ite_1
        Dw      ite_4
        Dw      ite_8
        Dw      ite_24

bmi2_fill_point    label   byte
        db      0                            ; Should never be invalid
        db      ite_cBitCount - ite_ulIdentifier
        db      ite_ulCompression - ite_ulIdentifier
        db      ite_cbImage - ite_ulIdentifier
        db      ite_cxResolution - ite_ulIdentifier
        db      ite_cyResolution - ite_ulIdentifier
        db      ite_cclrUsed - ite_ulIdentifier
        db      ite_cclrImportant - ite_ulIdentifier
        db      ite_usUnits - ite_ulIdentifier
        db      ite_usReserved - ite_ulIdentifier
        db      ite_usRecording - ite_ulIdentifier
        db      ite_usRendering - ite_ulIdentifier
        db      ite_cSize1 - ite_ulIdentifier
        db      ite_cSize2 - ite_ulIdentifier
        db      ite_ulColorEncoding - ite_ulIdentifier
        db      ite_ulIdentifier - ite_ulIdentifier

DEFAULT_VALUE      equ    000000000h

page
;/***************************************************************************
;*
;* FUNCTION NAME =  bmc_int_to_ext 
;*
;* DESCRIPTION   = Bitmap conversion, internal format to external 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         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = # of scanlines translated 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes ds,nothing
        assumes es,nothing

cProc   bmc_int_to_ext,<NEAR,PASCAL,PUBLIC,NODATA,NONWIN>,<di,ds>

        parmW   npbm                    ; Bitmap
        parmD   pbmi                    ; -> to bitmap info block
        parmD   pBuf                    ; -> buffer of source bits
        parmD   cyScans                 ; Number of scans to copy
        parmD   iStart                  ; First scan to copy
        parmD   pClrTbl                 ; -> color table to use
        parmW   npddc                   ; DDC

        localW  ScansCopied             ; number of scanlines copied
        localW  ScanCount               ; number of scanlines to copy
        localW  ScanPixels              ; width in pixels of the bitmap
        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  EtiProc                 ; -> pixel converter routine
        localW  HugeScansLeft           ; count of scans left in huge segment
        localW  BufferAdjust            ; alignment for each scan of buffer
        localD  DestScanLen             ; length of one buffer scanline
        localB  fbsd                    ; bunch of flags
        localV  ColorXlate,%(SIZE_HW_PAL*(SIZE RGB2))
        localW  rgb_size                ; old = 3 bytes, new = 4 bytes
        localB  fbPal                   ; palette flags
ITE_PALETTE     equ     00000001b       ; palette is selected into DC
ITE_PAL_INDICES equ     00000010b       ; return palette indices
        localD  pPalSeg                 ; devpal_pPalSeg for palette if exists
        localV  FakePal,%((SIZE PALSEG)+(SIZE PALCLR * 16))
cBegin

        CPUMode 386
        push    esi
        CPUMode 286

ifdef   FIREWALLS
        Mov     Ds,BitmapData
        assumes Ds,Data
        Mov     Bx,npbm
        Cmp     [Bx].bm_sd.sd_usId,SURFACE_IDENT
        Jne     ite_not_a_bitmap
        Test    [Bx].bm_sd.sd_fb,SD_DEVICE
        Jz      ite_its_a_Bitmap
ite_not_a_bitmap:
        rip     text,<Bitmap Conversions - Surface is not a bitmap>
ite_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     ite_log_error
        mov     bx,PMERR_INV_LENGTH_OR_COUNT
        cmp     cyScans.hi,ax
        je      ite_numbers_ok
ite_log_error:
        xchg    ax,bx
        save_error_code
        mov     ax,-1
ite_get_out:
        jmp     ite_exit

ite_inv_format:
        mov     bx,PMERR_INV_INFO_TABLE
        jmp     ite_log_error

ite_numbers_ok:
        Les     Bx,pbmi                 ; validate bitmap info structure
        assumes Es,nothing
        xor     cx,cx                   ; only check required fields
        Call    far_check_bitmap_info
        Jcxz    ite_inv_format

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

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

        Mov     Di,npbm
        mov     ax,[di].bm_sd.sd_cx     ;Must set height and width before
        mov     ScanPixels,ax           ;  checking for a null bitmap
        mov     dx,[di].bm_sd.sd_cy     ;Preserve AX and DX until height
        mov     BitmapHeight,dx         ;and width are set below
        CPUMode 386
        cmp     es:[bx].bmi2_cbFix,SIZE BITMAPINFOHEADER
        CPUMode 286
        jne     ite_new_header
        mov     es:[bx].bmi_cx,ax
        mov     es:[bx].bmi_cy,dx
        mov     rgb_size,(size RGB)
        jmp     ite_done_with_bmi
ite_new_header:                         ; fill in remaining fields
        assumes ds,Data
        push    si                      ; save si
        assert  es:[bx].bmp2_cbFix.hi,E,0   ; cbFix must be valid by this point
        mov     si,es:[bx].bmp2_cbFix.lo
        assert  si,LE,64
        .errnz  (SIZE BITMAPINFOHEADER2)-64
        shr     si,1
        assert  NC
        add     si,DataOFFSET ok_cbFix
        CPUMode 386
        movzx   si,[si]
        CPUMode 286
        assert  si,NE,0                 ; cbFix not invalid
        add     si,BitmapOFFSET bmi2_fill_point
        CPUMode 386
        movzx   si,cs:[si]
        CPUMode 286
        add     si,BitmapOFFSET ite_ulIdentifier
        jmp     si
ite_ulIdentifier:
ite_ulColorEncoding:
ite_cSize2:
        CPUMode 386
        mov     es:[bx].bmi2_cSize2,DEFAULT_VALUE
ite_cSize1:
        mov     es:[bx].bmi2_cSize1,DEFAULT_VALUE
ite_usRendering:
ite_usRecording:
ite_usReserved:
ite_usUnits:
        mov     es:[bx].bmi2_usUnits,BRU_METRIC
ite_cclrImportant:
        mov     cx,es:[bx].bmi2_cBitCount
        mov     esi,1
        shl     si,cl              ;CL is taken mod 32 by the instruction
        mov     es:[bx].bmi2_cclrImportant,esi
        jmp     SHORT ite_already_computed_colors
ite_cclrUsed:
        mov     cx,es:[bx].bmi2_cBitCount
        mov     esi,1
        shl     si,cl              ;CL is taken mod 32 by the instruction
ite_already_computed_colors:
        mov     es:[bx].bmi2_cclrUsed,esi
ite_cyResolution:
        mov     es:[bx].bmi2_cyResolution,DEFAULT_VALUE
ite_cxResolution:
        mov     es:[bx].bmi2_cxResolution,DEFAULT_VALUE
ite_cbImage:
        mov     es:[bx].bmi2_cbImage,DEFAULT_VALUE
        CPUMode 286
ite_ulCompression:
ite_cBitCount:
        mov     es:[bx].bmi2_cx.lo,ax
        mov     es:[bx].bmi2_cy.lo,dx
        mov     es:[bx].bmi2_cx.hi,0
        mov     es:[bx].bmi2_cy.hi,0
        mov     rgb_size,(SIZE RGB2)
        pop     si                      ; restore si

ite_done_with_bmi:

;/*
;** See if there's a palette in the ddc.
;*/

        CPUMode 386
        mov     fbPal,0                 ;assume no palette
        mov     di,npddc
        test    [di].ddc_fbBelow,DDC_PALETTE
        jz      @F
        or      fbPal,ITE_PALETTE
@@:
        mov     di,[di].ddc_npdevpal
        mov     cx,[di].devpal_pPalSeg.lo
        mov     dx,[di].devpal_pPalSeg.hi
        mov     pPalSeg.lo,cx
        mov     pPalSeg.hi,dx

        cmp     es:[bx].bmi2_cbFix,bmi2_ulColorEncoding
        jbe     @F
        cmp     es:[bx].bmi2_ulColorEncoding,BCE_PALETTE
        jne     @F
        test    fbPal,ITE_PALETTE
        njz     ite_inv_format
        or      fbPal,ITE_PAL_INDICES
@@:
        CPUMode 286


        Mov     Di,npbm
        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     ite_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      ite_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

ite_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
        Cmp     Cx,Bx                   ;If starting scan is outside bitmap
        Jb      @F                      ;  want count to become 0 so we'll
        mov     cx,bx                   ;  exit after color table is set
@@:     Sub     Bx,Cx                   ;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
        Add     Di,es:[di].bmi2_cbFix.lo        ; Es:Di --> where color table is
        Call    Si
        assumes ds,nothing

;/*
;** If pBuf is NULL, it is an inquiry and we have retreived all the information.
;*/

        CPUMode 386

        cmp     pBuf,0                  ;is it an inquiry?
        je     ite_xfered_all

        CPUMode 286

        cmp     ScanCount,0
        nje     ite_xfered_all


;/*
;**       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      ite_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

ite_huge_bitmap:
        Add     Dx,Cx                   ; show in next segment
        Sub     Ax,Bx                   ; see if in this segment
        Jnc     ite_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
        Jl      ite_finish_y_calc       ;  we'll skip huge bitmap stuff
        And     fbsd,not SD_HUGE

ite_finish_y_calc:
        Add     Dx,lp_bits.sel          ; source is our bitmap
        Mov     Ds,Dx
        assumes Ds,nothing

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

        Les     Di,pBuf                 ; dest is user's buffer (this pointer
        assumes Es,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,DestScanLen.hi
        Mul     Cx
        Xchg    Ax,Bx
        Mov     Ax,DestScanLen.lo
        Mul     Cx
        Add     Dx,Bx                   ; Dx:Ax = total bytes of buffer needed
        Add     Ax,Di
        Adc     Dx,0                    ; Dx:Ax = last address + 1
        jz      @F                      ; won't cross a segment boundary
        or      fbsd,CAN_CROSS_SEG      ; can cross a segment boundary
@@:
        mov     ax,DestScanLen.lo       ; I'm inserting this code to make
        mov     dx,DestScanLen.hi       ; DestScanLen not include the dword
        sub     ax,BufferAdjust         ; padding from here on.
        sbb     dx,0
        mov     DestScanLen.lo,ax
        mov     DestScanLen.hi,dx

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

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

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

        Dec     ScanCount
        Jz      ite_xfered_all          ; transfered all scans

        Add     Di,BufferAdjust         ; align dest to dword boundary
        Jnc     @F                      ; no segment crossing from this...
        Call    GetNextSelector         ; advance to next segment
        Jc      ite_xfered_all          ; make believe we finished
@@:

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

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

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

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

        Jmp     ite_next_scan


ite_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,Di                   ; if the entire scan shows, then
        Xor     Dx,Dx                   ; we can use the normal code
        Add     Ax,DestScanLen.lo
        Adc     Dx,DestScanLen.hi       ; SrcScanLen may be > 64K
        Jz      ite_in_segment          ; it won't cross a segment boundary
        Stc                             ; indicate segment crossing
        Jmp     ite_in_segment          ; now continue...


;/*
;** compute and save the size of the bitmap extracted
;*/

ite_xfered_all:
        les     bx,pbmi                 ;calculate the number of bytes returned
        assumes es,nothing

        CPUMode 386

        cmp     es:[bx].bmp2_cbFix,bmp2_cbImage
        jbe     short ite_return_val
        mov     ax,es:[bx].bmp2_cBitCount
        mul     es:[bx].bmp2_cx.lo
        add     ax,31                   ;Don't forget 32 bit aligned
        adc     dx,0
        shrd    ax,dx,3
        and     ax,not 3
        mul     ScansCopied             ;multiply with the number of scans
        mov     es:[bx].bmp2_cbImage.lo,ax
        mov     es:[bx].bmp2_cbImage.hi,dx

        CPUMode 286

ite_return_val:
        Mov     Ax,ScansCopied          ; return number of scans copied
        Xor     Dx,Dx

ite_exit:
        Cwd
        fw_zero <cx,es>

        CPUMode 386
        pop     esi
        CPUMode 286

cEnd

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

        assumes Ds,nothing
        assumes Es,nothing

ite_1   Proc    Near

        Mov     cx,2                    ; two indices in destination
        Call    CreateMonoColorTable    ; so need just two table entries

        Sub     Bx,Bx                   ; a zero
        Mov     BufferAdjust,Bx         ; no buffer adjust ever needed

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

        Mov     Dx,BitmapOFFSET CopyI1E1  ; assume 1:1 copy

        Test    fbsd,SD_COLOR           ; a color source ?
        Jz      ite_1_have_proc         ; no...

        Mov     Cx,256                  ; need to create local xlate table
        Call    CreateXlateTable        ; create translation table
        Mov     Dx,BitmapOFFSET CopyI8E1  ; assume -> 8:1 specialist

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

        Ret

ite_1   Endp

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

        assumes ds,Data
        assumes es,nothing

ite_4   proc    near

        Mov     Bx,ScanPixels           ; # pixels in a src scan
        Mov     Ax,Bx                   ; save for below
        Inc     Bx                      ; round pixels to destination bytes
        Shr     Bx,1                    ; # bytes in destination
        Neg     Bx
        And     Bx,3                    ; # bytes to pad to dword boundary

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

        Test    fbsd,SD_COLOR           ; a color source ?
        Jnz     ite_4_color             ; yes...

;/*
;** Internal mono to external 4 bpp.
;*/

        Mov     cx,16                           ; # colors to set in dest color table
        Call    CreateMonoColorTable

        Mov     Dx,BitmapOFFSET CopyI1E4  ; -> 1:4 specialist

        Jmp     Short ite_4_have_proc

;/*
;** Internal color format to external 4 bpp bitmap. We have a choice internally of
;** fetching from a 4 or an 8 bit source based on load-time configuration
;** parameters.
;*/

ite_4_color:

        Sub     Ax,Ax                   ; no black-filled table entries
        Mov     Cx,16                   ; clone first 16 entries of RGB table
        Call    CreateColorColorTable   ; populate destination color table

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

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

        Ret

ite_4   Endp

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

        assumes Ds,nothing
        assumes Es,nothing

ite_8   Proc    Near

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

        Neg     Bx                      ; determine # bytes to pad to src dword
        And     Bx,3

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

;/*
;** Internal mono to external 8 bpp format.
;*/

        Mov     cx,256                          ; # colors in user color table
        Call    CreateMonoColorTable

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

        Jmp     Short ite_8_have_proc


;/*
;** Internal color bitmap to external 8 bpp format. We have a choice internally of
;** fetching from a 4 or an 8 bit source based on load-time configuration
;** parameters.
;*/

ite_8_color:

        Sub     Ax,Ax                   ; no black-filled table entries
        Mov     Cx,256                  ; will clone entire color table
        Mov     Dx,BitmapOFFSET CopyI8E8  ; load -> 8:8 specialist

ite_8_make_color_table:
        Call    CreateColorColorTable

ite_8_have_proc:

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

        Ret

ite_8   endp

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

        assumes Ds,Data
        assumes Es,nothing

        CPUMode 386
ite_24  Proc    Near

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

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

        Add     Ax,Bx                   ; Dx:Ax is now padded length of dest
        adc     dx,0
        Mov     DestScanLen.lo,Ax
        Mov     DestScanLen.hi,Dx       ; stuff dest scan length in bytes

        Test    fbsd,SD_COLOR           ; a color source ?
        Jnz     ite_24_color            ; take jump if yes

;/*
;** If we are supposed to return palette indices instead of an RGBs,
;** find the indices of the colors closest to black and white and return
;** those.  Otherwise, just save the copy routine and return.
;*/

        Mov     Dx,BitmapOFFSET CopyI1E24       ; assume returning RGBs
        test    fbPal,ITE_PALETTE               ; check for palette indices
        jz      ite_24_have_proc                ; if not, we're done

        xor     ax,ax
        farPtr  rgbIn,ax,ax
        cCall   far_rgb_to_ipc_with_pal,<rgbIn,pPalSeg>
        movzx   ax,al
        mov     word ptr ColorXlate[0],ax

        mov     ax,0FFFFh
        mov     dx,000FFh
        farPtr  rgbIn,dx,ax
        cCall   far_rgb_to_ipc_with_pal,<rgbIn,pPalSeg>
        movzx   ax,al
        mov     word ptr ColorXlate[2],ax

        Mov     Dx,BitmapOFFSET CopyI1E24       ;reload this address
        jmp     short ite_24_have_proc

;/*
;** Make a table of rgbs for the pels to map onto.
;**
;** Initialize the table of rgb's to zeroes, and set up some registers
;** used by both branches below.
;*/

ite_24_color:
        Mov     Di,Ss
        Mov     Es,Di
        assumes Es,nothing
        Lea     Di,ColorXlate           ; Es:Di is -> local color xlate table

        lds     si,pPalSeg
        assumes ds,nothing
        mov     bx,SIZE_HW_PAL
        palSize cx,ds,si,bx
        sub     bx,cx
        add     si,palseg_apalclr.palclr_rgb

;/*
;** Copy the rgb colors from the ddc to the ColorXlate table based on
;** whether or not there's a custom palette.
;*/

        test    fbPal,ITE_PALETTE
        jz      ite_24_def_pal

ite_24_copy_next_pal_rgb:
        lodsd
        and     eax,0FFFFFFh
        stosd
        add     si,(SIZE PALCLR)-(SIZE RGB2)
        loop    ite_24_copy_next_pal_rgb
        mov     cx,bx
        xor     eax,eax                 ; initialize table to blacks
        rep     stosd
        jmp     short ite_24_color_done
        .errnz  (SIZE RGB)  - 3
        .errnz  (SIZE RGB2) - 4

;/*
;** Use the default palette.  Since the default palette is split in the
;** hardware, and since default palette ipcs are the same for bitmaps and
;** device ddc's, just follow the realization table to place rgb's into
;** ColorXlate.
;*/

ite_24_def_pal:
        lea     edi,ColorXlate          ; Es:Di is -> local color xlate table
        xor     eax,eax                 ; initialize table to blacks
        push    cx
        mov     cx,SIZE_HW_PAL/4
        rep     stosd
        pop     cx

        xor     ebx,ebx
        lea     edi,ColorXlate          ; Es:Di is -> local color xlate table
ite_24_next_defpal_rgb:
        mov     bl,byte ptr [si].(palclr_bCur-palclr_rgb)
        xor     bh,bh
        rgbOff  ebx
        lodsd
        and     eax,0FFFFFFh
        mov     es:[ebx+edi],eax
        add     si,(SIZE PALCLR)-(SIZE RGB2)
        loop    ite_24_next_defpal_rgb

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

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

ite_24  Endp
        CPUMode 286

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE create_color_color_table  
;*
;* DESCRIPTION   = The color table for color source bitmaps is created.  The table     
;*                 will consists of the 16 fixed colors for the driver.  The remaining 
;*                 entries will be set to black, even though we will never generate    
;*                 those indicies.                                                     
;*
;*                 Registers Preserved:         
;*                       Bx,Bp,Ds,Es            
;*                 Registers Destroyed:         
;*                       Ax,Cx,Dx,Si,Di,FLAGS 
;*
;* INPUT         = ES:DI --> where color table would go                           
;*                 Ax    =   total number of color table entries to zero beyond CX
;*                 CX    =   total number of color table entries to copy from ours 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

        CPUMode 386
CreateColorColorTable   Proc    Near

        push    dx
        push    bx
        push    ds

        test    fbPal,ITE_PALETTE
        njnz    ccct_palette

;/*
;** Return the default palette.
;**
;** !!! Default palette is currently 16 colors.  In this case, the only
;**     difference between the 4 bpp and 8 bpp returned color tables is
;**     that the 8 bpp table is padded with zeroes.
;**
;**     If the default palette grows beyond 16 colors, change the code as
;**     follows:
;**
;**       4 bpp:  return the first 16 colors
;**       8 bpp:  return all the colors, zero padding to 256 (can we just set
;**                 cclrUsed instead?)
;*/

        cmp     cx,16
        je      ccct_defpal_8_to_4

        xor     ebx,ebx
        mov     si,DataOFFSET palsegDefPal
        cmp     rgb_size,(size RGB)
        je      ccct_defpal_rgb_8_setup

;/*
;** New format rgb's (dwords).
;*/

        push    di
        xor     edi,edi                 ;clear high word of edi
        pop     di
        xor     eax,eax
        push    di
        mov     cx,256
        rep     stosd                   ; initialize table to black
        pop     di

        mov     cx,256
        add     si,palseg_apalclr.palclr_rgb

ccct_defpal_rgb2_8:
        movsw
        movsb
        inc     di
        add     si,5
        loop    ccct_defpal_rgb2_8
        jmp     ccct_exit

;/*
;** Old format rgb's (three-byte quantities).
;*/

ccct_defpal_rgb_8_setup:
        push    di
        xor     edi,edi
        pop     di
        xor     eax,eax
        push    di
        mov     cx,(SIZE_HW_PAL*3)/4
        rep     stosd                   ; initialize table to black
        pop     di

        palSize cx,ds,si,SIZE_HW_PAL
        add     si,palseg_apalclr.palclr_rgb
ccct_defpal_rgb_8:
        mov     bl,byte ptr [si].(palclr_bCur-palclr_rgb)
        xor     bh,bh
        imul    bx,bx,size RGB
        lodsd
        mov     es:[bx+di],ax
        shr     eax,16
        mov     es:[bx+di+2],al
        add     si,(size PALCLR)-(size RGB2)
        loop    ccct_defpal_rgb_8
        jmp     ccct_exit

;/*
;** The target format is 4 bpp.
;*/

ccct_defpal_8_to_4:
        mov     si,DataOFFSET PalColor16
        mov     cx,16

ifdef FIREWALLS
        push    ax
        push    si
        sub     si,palseg_apalclr+palclr_rgb
        palSize ax,ds,si
        cmp     ax,cx
        je      ccct_defpal_count_ok
        rip     text,<ccct: default palette more than 16 colors now!>
ccct_defpal_count_ok:
        pop     si
        pop     ax
endif

        cmp     rgb_size,(size RGB)
        je      ccct_defpal_rgb_loop

;/*
;** New rgb format (RGB2).  In this case, rgb's are dwords.
;*/

        assert  rgb_size,E,<size RGB2>
        xchg    ax,dx                   ;save # words to zero-fill in DX
ccct_defpal_rgb2_loop:
        lodsd
        and     eax,0FFFFFFh
        stosd
        add     si,(size PALCLR)-(size RGB2)
        loop    ccct_defpal_rgb2_loop

        xchg    dx,cx                   ;move # words to zero-fill to CX
        xor     eax,eax
        rep     stosd
        jmp     ccct_exit
        .errnz  (size RGB2)-4

;/*
;** Old rgb format (RGB).  In this case, rgb's are three-byte quantities.
;*/

ccct_defpal_rgb_loop:
        movsw
        movsb
        add     si,(size PALCLR)-(size RGB)
        loop    ccct_defpal_rgb_loop

;/*
;** Fill the remainder of the user color table with black.  Fill 3*AX/4 dwords.
;*/

        mov     cx,ax                   ; # entries to black fill
        add     cx,cx
        add     cx,ax
        .errnz  (size RGB)-3

ifdef FIREWALLS
        test    cx,011b
        jz      ccct_defpal_rgb_good_count
        rip     text,<ccct: bad black fill count>
ccct_defpal_rgb_good_count:
endif
        shr     cx,2
        assert  NC
        xor     eax,eax                 ; black RGB (0,0,0)
        rep     stosd                   ; black fill remainder of user table
        jmp     ccct_exit

;/*
;** There is a palette selected into the DC along with this bitmap.  To
;** convert from high bpp to low, take as many colors from the front of
;** the palette as necessary, and map all the others onto these.  To
;** convert from low to high, take the palette as is and fill the extra
;** color entries with black (as the old code did).
;**
;** DS:SI  --> ddc
;** ES:DI  --> where color table is
;** AX      =  # user color table words to zero beyond CX
;** CX      =  # user color table words to copy from ours
;*/

ccct_palette:
        cmp     cx,16           ; who is calling? is it 8bpp to 4bpp?
        je      ccct_8_to_4_pal
        assert  cx,E,256

        test    fbPal,ITE_PAL_INDICES
        jz      ccct_not_pal_indices

;/*
;** Palette indices are to be returned.  This imples that we have 4-byte
;** indices to pass back.  Pass back the identity table.
;*/

        xor     eax,eax
@@:
        stosd
        inc     eax
        loop    @B
        jmp     ccct_exit

ccct_not_pal_indices:
        lds     si,pPalSeg
        assumes ds,nothing
        mov     dx,SIZE_HW_PAL
        palSize cx,ds,si,dx
        sub     dx,cx
        add     si,palseg_apalclr.palclr_rgb

        cmp     rgb_size,(size RGB)
        je      ccct_copy_rgb
        assert  rgb_size,E,<SIZE RGB2>

        xchg    ax,dx
ccct_copy_rgb2:
        lodsd
        and     eax,0FFFFFFh
        stosd
        add     si,(SIZE PALCLR)-(SIZE RGB2)
        loop    ccct_copy_rgb2
        xchg    cx,dx
        xor     eax,eax
        rep     stosd
        jmp     ccct_exit
        .errnz  (SIZE RGB)  - 3
        .errnz  (SIZE RGB2) - 4

ccct_copy_rgb:
        movsw
        movsb
        add     si,(SIZE PALCLR)-(SIZE RGB)
        loop    ccct_copy_rgb
        mov     cx,dx                   ;DX = # colors to black-fill
        add     dx,dx                   ; 
        add     cx,dx                   ;CX = 3*(# colors)
        mov     dx,cx                   ; 
        and     dx,011b                 ;DX = 3*(# colors) mod 4
        shr     cx,2                    ;CX = 3*(# colors) / 4
        xor     eax,eax
        rep     stosd                   ;fill as much as possible by dwords
        mov     cx,dx
        rep     stosb                   ;fill remainder by bytes
        njmp    ccct_exit
        .errnz  (SIZE RGB)-3

;/*
;** Converting 8 bpp to 4 bpp.  Construct table to take all 256 indices
;** to first 16 colors.  Do this by first building a fake palette of the
;** first 16 entries in the real palette, then matching the real one to
;** the fake one.
;*/

ccct_8_to_4_pal:

;/*
;** Create a fake palette consisting of the first 16 used entries in the
;** real palette.
;*/

        farPtr  pPalFake,ss,bx
        lea     bx,FakePal
        save    <ax,es,di>
        cCall   BuildFakePalette,<pPalSeg,pPalFake,16>

;/*
;** Copy the fake palette colors into the caller's color table --
;** it's now legitimate.
;*/

        mov     cx,16

        test    fbPal,ITE_PAL_INDICES
        jz      ccct_not_pal_indices_4

;/*
;** Palette indices are to be returned.  This imples that we have 4-byte
;** indices to pass back.  Pass back the identity table.
;*/

        xchg    ax,dx                   ;save amount to black fill
        xor     eax,eax
@@:
        stosd
        inc     eax
        loop    @B
        xchg    ax,dx                   ;restore amount to black fill
        jmp     short ccct_not_pal_indices_4_black_fill

ccct_not_pal_indices_4:
        mov     bx,ss
        mov     ds,bx
        assumes ds,nothing
        lea     si,FakePal
        add     si,palseg_apalclr.palclr_rgb
        cmp     rgb_size,(SIZE RGB)
        je      ccct_move_pal_4_old_rgb
        assert  rgb_size,E,<SIZE RGB2>
@@:
        movsd
        .errnz  (SIZE RGB2)-4
        add     si,(SIZE PALCLR)-(SIZE RGB2)
        loop    @B

ccct_not_pal_indices_4_black_fill:
        mov     cx,ax
        xor     eax,eax
        rep     stosd
        .errnz  (SIZE RGB2)-4
        jmp     short ccct_8_to_4_pal_match_pals

ccct_move_pal_4_old_rgb:
        movsw
        movsb
        .errnz  (SIZE RGB)-3
        add     si,(SIZE PALCLR)-(SIZE RGB)
        loop    ccct_move_pal_4_old_rgb
        mov     cx,ax                   ; # entries to black fill
        add     ax,ax
        add     cx,ax
        xor     ax,ax                   ; black RGB (0,0,0)
        shr     cx,1
        assert  NC
        rep     stosw                   ; black fill remainder of user table

;/*
;** Match the real palette against the truncated one, saving the results
;** in ColorXlate.
;*/

ccct_8_to_4_pal_match_pals:
        farPtr  pPalFake,ss,bx
        farPtr  pXlatTbl,ss,ax
        lea     ax,ColorXlate
        lea     bx,FakePal
        cCall   MatchTwoPalettes,<pPalFake,pPalSeg,pXlatTbl,0>

ccct_exit:
        pop     ds
        pop     bx
        pop     dx
        ret
CreateColorColorTable   Endp
        CPUMode 286

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE create_mono_color_table 
;*
;* DESCRIPTION   = The destination bitmap mono color table is created.  All           
;*                 entries but the last entry in the color table will be set to       
;*                 an RGB of black (0,0,0).  The last entry in the color table        
;*                 will be set to white (255,255,255).                                
;*
;*                 Registers Preserved:         
;*                       BX,BP,DS,ES
;*                 Registers Destroyed:         
;*                       AX,CX,DX,DI,SI,FLAGS
;*
;* INPUT         = ES:DI --> where color table would go                           
;*                 CX    =   total number of color table entries to generate      
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,Data
        assumes Es,nothing

        CPUMode 386

CreateMonoColorTable    Proc    Near

        test    fbPal,ITE_PAL_INDICES
        jnz     cmct_pal_indices

;/*
;** Compute number of words in color table.  An even number of entries is assumed.
;*/

        dec     cx
        mov     ax,rgb_size
        mul     cx
        mov     cx,ax

;/*
;** All RGB triplets in the user color table will be set to black except
;** for the last which will be set to white.
;*/

        Sub     Ax,Ax                   ; get black
    Rep Stosb                           ; set color table to all black

        Not     Ax                      ; have white now

        Stosw                           ; store R,G
        Stosb                           ; then B
        cmp     rgb_size,(size RGB)
        je      short cmct_exit
        .errnz  (size RGB)-3
        .errnz  (size RGB2)-4
        inc     ax
        stosb

        jmp     short cmct_exit

;/*
;** We are supposed to return palette indices instead of an RGB array.
;** Find the indices of the colors closest to black and white and return
;** those.  We always return 4-byte array elements in this case.
;*/

cmct_pal_indices:
        xor     ax,ax
        farPtr  rgbIn,ax,ax
        cCall   far_rgb_to_ipc_with_pal,<rgbIn,pPalSeg>
        movzx   eax,al
        dec     cx
        rep     stosd

        mov     ax,0FFFFh
        mov     dx,000FFh
        farPtr  rgbIn,dx,ax
        cCall   far_rgb_to_ipc_with_pal,<rgbIn,pPalSeg>
        movzx   eax,al
        stosd

cmct_exit:
        Ret

        CPUMode 286

CreateMonoColorTable    Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CreateXlateTable
;*
;* DESCRIPTION   = The translation table for translating from our colors to user
;*                 mono format is generated                                     
;*
;*                 Registers Preserved:         
;*                       Bp,Ds                      
;*                 Registers Destroyed:             
;*                       Ax,Bx,Cx,Dx,Si,Di,Es,FLAGS 
;*
;* INPUT         = CX    =   total number of translation table entries 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes Ds,Data
        assumes Es,nothing

CreateXlateTable        Proc    Near

        Push    Ds
        test    fbPal,ITE_PALETTE
        jz      cxt_no_palette

;/*
;** There is a palette in the DDC.  The ColorXlate table will indicate
;** the closest match to black and white of every color in the palette.
;** Color table entries not in the palette will map to black.
;*/

        farPtr  pPalFake,ss,ax
        lea     ax,FakePal
        cCall   BuildFakeMonoPalette,<pPalFake>

        farPtr  pPalFake,ss,bx
        farPtr  pXlatTbl,ss,ax
        lea     ax,ColorXlate
        lea     bx,FakePal
        cCall   MatchTwoPalettes,<pPalFake,pPalSeg,pXlatTbl,0>

        errn$   CXT_Exit

;/*
;** No palette, so just grab the mono bits from the default color table.
;*/

cxt_no_palette:

CXT_Exit:

        Pop     Ds
        assumes Ds,Data
        Ret

CreateXlateTable        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE GetNextSelector
;*
;* DESCRIPTION   = The next destination selector (if it exists) will be loaded. 
;*
;*                 Registers Preserved:         
;*                       Ax,Bx,Cx,Dx,Si,Di,Bp,Ds
;*                 Registers Destroyed:         
;*                       Es                     
;*                       FLAGS                  
;* INPUT         = ES --> current dest selector 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ES --> new dest selector if next one exists and is valid 
;* 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

GetNextSelector Proc Near

        Push    Ax
        Push    Dx

        Mov     Dx,Es
        Add     Dx,DOSHUGEINCR

        Lar     Ax,Dx                   ; user segment accessible ?
        stc                             ; in case of failure
        jnz     @F                      ; couldn't access next selector
        Mov     Es,Dx                   ; access is safe
        assumes Es,nothing
        clc                             ; show access is ok
@@:

        Pop     Dx
        Pop     Ax

        Ret

GetNextSelector Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copyI1E1
;*
;* DESCRIPTION   = Source mono pixels are copied into the internal mono bitmap. 
;*                                                                                     
;*                 This routine is used for:                                         
;*                     internal mono to external mono
;*                     external mono to internal mono
;*
;*                 Registers Preserved:         
;*                       DX,BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,CX,DX,SI,FLAGS
;*
;* INPUT         = DS:SI --> source                  
;*                 ES:DI --> destination             
;*                 CX     =  number of bytes to copy  
;*                 Direction flag cleared             
;*                 '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 destination byte less BufferAdjust 
;*                 Direction flag cleared         
;*
;* 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

CopyI1E1        Proc    Near

        Jc      CI1E1_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

CI1E1_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,Di                   ; 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    GetNextSelector         ; try to get next selector
        Jc      CI1E1_Slow_Exit         ; return with an error, 'C' set

        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

CI1E1_Slow_Exit:

        Ret
CopyI1E1        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copyI8E1
;*
;* DESCRIPTION   = Internal 8 bpp format is copied into external mono format.
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,DX,SI,DI,FLAGS
;*
;*                 Calls:
;*                       GetNextSelector
;*
;* INPUT         = DS:SI --> source
;*                 ES:DI --> destination
;*                  X      = number of bytes to xlate
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte less BufferAdjust 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;**************************************************************************/

        assumes Ds,nothing
        assumes Es,nothing

CopyI8E1        Proc    Near

        Add     Cx,3                    ; round up to src dwords
        And     Cl,Not 3                ; lo bits are extraneous
        Shr     Cx,1                    ; # source words to xfer

        Mov     Dl,00010001b            ; write a dest byte every 4 src words

        test    fbPal,ITE_PALETTE
        jnz     CI8E1_pal

CI8E1_lp0:
        Lodsw                           ; fetch 2 pixels of source
        add     al,1                    ; CY = MONO_BIT = 1 iff AL = FF
        Rcl     Dh,1                    ; add to building dest byte
        Mov     Al,Ah
        add     al,1                    ; CY = MONO_BIT = 1 iff AL = FF
        Rcl     Dh,1                    ; add to building dest byte
        Rol     Dl,1                    ; time to write dest byte yet ?
        Jnc     @F                      ; not yet...
        Mov     Al,Dh                   ; store the built destination byte
        Stosb
        Or      Di,Di                   ; check for destination segment ovf
        Jz      CI8E1_NextSeg           ; advance to next segment
CI8E1_Reentry:
@@:
        Loop    CI8E1_lp0               ; for all source pixels...

        cmp     Dl,00010001b            ; partial last byte ?
        je      CI8E1_no_partial        ; no...
@@:
        shl     dh,2                    ; fill out the rest of the byte
        rol     dl,1                    ; with zeros.
        jnc     @B
        clc                             ; we clear carry flag
        Mov     Al,Dh                   ; yes, get it
        Stosb                           ; store it
CI8E1_no_partial:
        ret

CI8E1_pal:
        Lea     Bx,ColorXlate           ; -> translation table

CI8E1_pal_lp0:
        Lodsw                           ; fetch 2 pixels of source
        Xlat    Ss:[Bx]                 ; first pixel to mono bit
        Shr     Al,1                    ; MONO_BIT to carry
        Rcl     Dh,1                    ; add to building dest byte
        Mov     Al,Ah
        Xlat    Ss:[Bx]                 ; next pixel to mono bit
        Shr     Al,1                    ; MONO_BIT to carry
        Rcl     Dh,1                    ; add to building dest byte
        Rol     Dl,1                    ; time to write dest byte yet ?
        Jnc     @F                      ; not yet...
        Mov     Al,Dh                   ; store the built destination byte
        Stosb
        Or      Di,Di                   ; check for destination segment ovf
        Jz      CI8E1_pal_NextSeg       ; advance to next segment
CI8E1_pal_Reentry:
@@:
        Loop    CI8E1_pal_lp0           ; for all source pixels...

        cmp     Dl,00010001b            ; partial last byte ?
        je      CI8E1_pal_no_partial    ; no...
@@:
        shl     dh,2                    ; fill out the rest of the byte
        rol     dl,1                    ; with zeros.
        jnc     @B
        clc                             ; we clear carry flag
        Mov     Al,Dh                   ; yes, get it
        Stosb                           ; store it
CI8E1_pal_no_partial:

        Ret                             ; success return, 'C'=0


CI8E1_NextSeg:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     CI8E1_Reentry           ; if successful reenter loop
        Ret                             ; else return with an error, 'C' set

CI8E1_pal_NextSeg:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     CI8E1_pal_Reentry       ; if successful reenter loop
        Ret                             ; else return with an error, 'C' set

CopyI8E1        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copyI1E4
;*
;* DESCRIPTION   = copy internal 1 bit to external 4 bit packed pixel                       
;*                                                                                          
;*                 The destination is filled with the source data, with each source         
;*                 bit expanded to a nibble in the destination.                             
;*                                                                                          
;*                 It is the caller's responsibility to handle all segment crossings,       
;*                 and to ensure that there are enough bytes of destination available       
;*                 to hold the data.                                                        
;*
;*                 This routine is used for:
;*                     internal mono to external four-bit packed pixels
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,DX,SI,FLAGS   
;*
;* INPUT         = DS:SI --> source                   
;*                 ES:DI --> destination              
;*                 CX      = number of bytes to xlate
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 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

CopyI1E4        Proc    Near

        Inc     Cx                      ; round up to 2 pixel boundary
        shr     cx,1                    ; Number of bytes to output.

        Mov     Dl,10001000b            ; fetch src byte every 4 dest bytes

CI1E4_lp0:

        Rol     Dl,1                    ; time to fetch new src byte ?
        Jnc     @F                      ; no...
        Lodsb                           ; get 8 src pixels
        Mov     Dh,Al                   ; store here
@@:

        Shl     Dh,1                    ; next src pixel to carry
        Sbb     Al,Al                   ; replicated in Al
        Shl     Dh,1                    ; next src pixel to carry
        Sbb     Ah,Ah                   ; replicated in Ah
        And     Ax,0ff0h                ; isolate nibbles
        Or      Al,Ah                   ; combine 2 pixels in Al
        Stosb

        Or      Di,Di                   ; dest ovf segment ?
        Jz      CI1E4_NextSeg           ; yes, advance to next segment...
CI1E4_Reentry:

        Loop    CI1E4_lp0               ; for all pixels to copy...

        Ret                             ; success return, 'C' reset


CI1E4_NextSeg:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     CI1E4_Reentry           ; if successful reenter loop
        Ret                             ; else return with an error, 'C' set

CopyI1E4        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copy_I8E4
;*
;* DESCRIPTION   = 
;*
;*         Internal 8 bpp pixels are copied into the external 4 bpp bitmap
;*       
;*        The RGBs for the first 16 colors in the default color table have
;*        been reordered in the color table we are going to use here.  They
;*        have been placed in "natural order".  This allows us to easily turn
;*        the 8 bit ipc into a 4 bit index into this new table by direct
;*        examination of the bits in the ipc (i.e. the red intensity, etc.).
;*       
;*        This mapping will give reasonable results in general, and in
;*        particular it will give back the same index that was set if
;*        the app originally asked for 4 bits/pel and only used 16 default
;*        indicies.
;*       
;*        The mapping below clearly depends on knowing exactly what ipc values
;*        are in the default color table.  Changes there must be reflected here.
;*       
;*       
;*         1st 16 Def Color Tbl Entries     index  R G B      R   G  B
;*         ----------------------------     -----  -----     --- --- --
;*         white         SYSCLR_WINDOW       255   7 7 3  =  111 111 11
;*         blue                              3     0 0 3  =  000 000 11
;*         red                               224   7 0 0  =  111 000 00
;*         pink (magenta)                    227   7 0 3  =  111 000 11
;*         green                             28    0 7 0  =  000 111 00
;*         turquoise (cyan)                  31    0 7 3  =  000 111 11
;*         yellow                            252   7 7 0  =  111 111 00
;*         black         SYSCLR_WINDOWTEXT   0     0 0 0  =  000 000 00
;*       
;*         dark gray                         37    1 1 1  =  001 001 01
;*         dark blue                         1     0 0 1  =  000 000 01
;*         dark red                          64    2 0 0  =  010 000 00
;*         purple                            65    2 0 1  =  010 000 01
;*         dark green                        8     0 2 0  =  000 010 00
;*         dark turquoise                    9     0 2 1  =  000 010 01
;*         mustard                           72    2 2 0  =  010 010 00
;*         gray                              73    2 2 1  =  010 010 01
;*                                                                                         
;*                 Registers Preserved:                                                                             
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,DX,SI,FLAGS   
;*
;*                 Calls:
;*                       GetNextSelector
;*
;* INPUT         = DS:SI --> source                                           
;*                 ES:DI --> destination                                      
;*                 CX      = number of pixels to xlate
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C'     =       0 if pixels transferred ok       
;*                 'C'     =       1 if could not get next selector
;**************************************************************************/

bGreyMap label   byte
    db  0   ; 0    black (argbDefCT16Reorg)
    db  7   ; 1    dark grey
    db  0   ; 2
    db  0   ; 3
    db  0   ; 4
    db  0   ; 5
    db  0   ; 6
    db  0   ; 7
    db  0   ; 8
    db  0   ; 9
    db  0   ; 10
    db  0   ; 11
    db  0   ; 12
    db  0   ; 13
    db  8   ; 14   light grey
    db  15  ; 15   white

        assumes Ds,nothing
        assumes Es,nothing

;/*
;** The strategy below is to set the intensity bit if ANY of the
;** primary colors is intense, and then set the R,G or B bits if
;** ANY of the corresponding primary exists.
;*/

.errnz  ((0111111b SHR 1) + 1 - cGreys)

convert8to4     macro
        local   no_intensity_bit
        local   add_intensity_bit
        local   not_grey
        local   got_my_index
        local   there_is_blue

        lodsb                   ; get the ipc
        cmp     al,(cGreys/2)
        jg      not_grey
        cmp     al,256-(cGreys/2)
        jl      not_grey

        and     al,01111111b    ; grab only grey bits

        shr     al,3            ; map bits into black grey1 grey2 or white
        push    bx
        xor     bx,bx
        mov     bl,al
        shl     ah,4            ; if this is the second pass don't hit hi bits
        or      ah,cs:bGreyMap[bx]
        pop     bx

        jmp     short   got_my_index

;/*
;** R 0,1,2,3,4 are dim 5,6 are bright
;** G 0,1,2,3,4 are dim 5,6,7 are bright
;** B 0,1,2 are dim and 3 is bright
;**
;** If we made B 0,1 dim and 2,3 bright then DarkBlue would have to be 1
;** which wou can't see on a black background.  So VIO window color would
;** look incorrect.
;*/

not_grey:
        sub     al,(cGreys/2)
        test    al,10010011b    ; are any of R,G or B intense?
        jz      no_intensity_bit
        test    al,01101111b    ; are any of R,G or B intense?
        jz      no_intensity_bit
add_intensity_bit:
        stc                     ; Yep; its intense
no_intensity_bit:
        rcl     ah,1            ; Roll in the intensity bit.

        cmp     al,00100000b    ; Is any red?
        cmc
        rcl     ah,1            ; Set red bit

        and     al,00011111b    ; Remove the (red) bits already tested.
        cmp     al,00000100b    ; Is there any green?
        cmc
        rcl     ah,1            ; Set green bit

        and     al,00000011b    ; Remove the (red & green) bits already tested.
        stc
        jnz     there_is_blue
        clc
there_is_blue:
        rcl     ah,1            ; Set blue bit.

got_my_index:
        endm

CopyI8E4        Proc    Near

        inc     cx                      ; round up to src words
        shr     cx,1                    ; now # full src words to xfer

        test    fbPal,ITE_PALETTE
        jnz     copyi8e4_with_pal

        CPUMode 386
        push    bx
        push    dx
        push    gs
        mov     gs,BitmapData
        assumes gs,Data
        mov     bx,DataOFFSET aIPC256toIPC16
        push    bx
        xor     dh,dh

CI8E4_lp0:

        lodsb
        mov     dl,al
        pop     bx
        push    bx
        add     bx,dx
        mov     al,byte ptr gs:[bx]

        mov     ah,al
        shl     ah,4
        lodsb
        mov     dl,al
        pop     bx
        push    bx
        add     bx,dx
        mov     al,byte ptr gs:[bx]

        or      al,ah
        stosb                           ; store 2 dest pixels
        or      di,di                   ; check for dest segment ovf
        jz      CI8E4_NextSeg           ; advance to next segment
CI8E4_Reentry:
        loop    CI8E4_lp0               ; for all pixels...
        pop     bx
        pop     gs
        pop     dx
        pop     bx

        clc
        CPUMode 286
        ret                             ; success return, 'C'=0 from Or above

CI8E4_NextSeg:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     CI8E4_Reentry           ; if successful reenter loop

        pop     bx
        pop     gs
        pop     dx
        pop     bx

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

;/*
;** Copy a row of pels, mapping each one through the xlat table.
;** This looks exactly like the above, except that the "and al,0Fh"
;** instructions are replaced by "xlat ss:[bx]".
;*/

copyi8e4_with_pal:

        lea     bx,ColorXlate

copyi8e4_with_pal_top:
        lodsb
        xlat    ss:[bx]
        shl     al,4
        mov     ah,al
        lodsb
        xlat    ss:[bx]
        or      al,ah
        stosb
        or      di,di
        jz      ci8e4_nextseg_with_pal
ci8e4_reentry_with_pal:
        loop    copyi8e4_with_pal_top
        ret

ci8e4_nextseg_with_pal:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     ci8e4_reentry_with_pal  ; if successful reenter loop
        Ret                             ; else return with an error, 'C' set
CopyI8E4        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copy_I1E8
;*
;* DESCRIPTION   = copy internal 1 bit to external 8 bit packed pixel                       
;*                                                                                          
;*                 The destination is filled with the source data, with each source         
;*                 bit expanded to a byte in the destination.                               
;*                                                                                          
;*                 It is the caller's responsibility to handle all segment crossings,       
;*                 and to ensure that there are eight bytes of destination available        
;*                 to hold each byte of source data.                                        
;*                                                                                      
;*                 This routine is used for:                                            
;*                     internal mono to external eight-bit packed pixels                
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,DX,SI,DI,FLAGS
;*                 Calls:   GetNextSelector
;*
;* INPUT         = DS:SI --> source                   
;*                 ES:DI --> destination
;*                 CX      =  number of bytes to xlate
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 
;*
;* 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

CopyI1E8        Proc    Near

        Mov     Dl,10000000b            ; fetch src byte every 8 dest bytes

CI1E8_lp0:

        Rol     Dl,1                    ; time to fetch new src byte ?
        Jnc     @F                      ; no...
        Lodsb                           ; get 8 src pixels
        Mov     Dh,Al                   ; store here
@@:

        Shl     Dh,1                    ; next src pixel to carry
        Sbb     Al,Al                   ; replicated in Al
        Stosb

        Or      Di,Di                   ; dest ovf segment ?
        Jz      CI1E8_NextSeg           ; yes, advance to next segment...
CI1E8_Reentry:

        Loop    CI1E8_lp0               ; for all pixels to copy...

        Ret                             ; success return, 'C' reset


CI1E8_NextSeg:

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

        Call    GetNextSelector         ; try to get next selector
        Jnc     CI1E8_Reentry           ; if successful reenter loop
        Ret                             ; else return with an error, 'C' set

CopyI1E8        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE CopyI8E8
;*
;* DESCRIPTION   = Internal 8 bpp pixels are copied into the external 8 bpp bitmap          
;*                                                                                          
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;*                 Calls:   
;*                       GetNextSelector
;*
;* INPUT         = DS:SI --> source                   
;*                 ES:DI --> destination              
;*                 CX     =  number of bytes to xlate 
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 
;*
;* 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

CopyI8E8        Proc    Near

        Jc      CI8E8_Slow              ; dest will ovf segment...

        Shr     Cx,1                    ; # full words to xfer
    Rep Movsw
        Rcl     Cx,1                    ; process possible trailing byte
    Rep Movsb

        Ret                             ; return, 'C'=0 from Rcl above


;/*
;** The destination scan will cross a segment boundary
;*/

CI8E8_Slow:

        Mov     Dx,Cx                   ; clone total byte count

        Mov     Cx,Di                   ; 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    GetNextSelector         ; try to get next selector
        Jc      CI8E8_Slow_Exit         ; return with an error, 'C' set

        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

CI8E8_Slow_Exit:

        Ret

CopyI8E8        Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copy_i1e24      
;*
;* DESCRIPTION   = copy internal 1 bit to external 24 bit RGB                               
;*                                                                                          
;*                 The destination is filled with the source data, with each source         
;*                 bit expanded to a full RGB triplet in the destination.  The colors       
;*                 being translated are black and white, so no color lookup is required     
;*                                                                                          
;*                 It is the caller's responsibility to handle all segment crossings,       
;*                 and to ensure that there are 24 bytes of destination available to        
;*                 hold each source byte of data.                                       
;*                                                                                      
;*                 This routine is used for:                                            
;*                     internal mono to external RGB (24-bit packed pixels)            
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;*                 Calls:
;*                       rgb_to_ipc
;*                       GetNextSelector
;*
;* INPUT         = DS:SI --> source
;*                 ES:DI --> destination
;*                 CX     =  number of bytes to xlate 
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 
;*
;* 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

;/*
;** This macro assumes that the only return values are 000000h and 0FFFFFFh,
;** so it only needs to store one byte to know what to write for a destination
;** pixel.
;*/

store_2_24bpp_pels      macro
        Shl     Bl,1                    ; get a mono pixel
        Sbb     Ax,Ax                   ; replicate
        Stosw                           ; store R,G
        Shl     Bl,1                    ; get next mono pixel
        Sbb     Ah,Ah                   ; replicate
        Stosw                           ; store B from last, R from new
        Mov     Al,Ah
        Stosw                           ; store G,B from new
        endm

;/*
;** This macro must look up the value that a source pel maps onto.  Since
;** palette indices can exceed 255, it must fetch two bytes for each source
;** pel.  A palette index cannot exceed 0FFFFh, so the high byte of each
;** destination pel will be 0.
;*/

store_2_24bpp_pal_indices       macro
        shl     dh,1                    ; get a mono pixel
        setc    al                      ; put its value into AL
        cbw                             ; make it a word
        shl     ax,1                    ; make it a word index
        xchg    ax,si                   ; put it in SI
        mov     cx,word ptr ss:ColorXlate[si]   ; look up palette index
        shl     dh,1                    ; repeat for second mono pixel
        setc    al
        cbw
        shl     ax,1
        xchg    ax,si
        mov     ax,word ptr ss:ColorXlate[si]
        xchg    ax,cx                   ; swap places for stosw
        stosw                           ; store two bytes of current
        xor     al,al                   ; high byte of current will always be 0
        mov     ah,cl                   ; low byte of next comes from CL
        stosw                           ; store bytes bridging dest pels
        mov     al,ch                   ; middle byte of next comes from CH
        xor     ah,ah                   ; high byte of next will always be 0
        stosw                           ; store last two bytes of next
        endm


        CPUMode 386

CopyI1E24       Proc    Near

        Jc      CI1E24_Slow             ; destination will ovf segments...

        Mov     Dx,Cx                   ; clone pixels to xfer
        Shr     Cx,3                    ; # full src bytes to xfer
        And     Dx,7                    ; # pixels in partial src byte to xfer

        test    fbPal,ITE_PAL_INDICES
        jnz     CI1E24_pal

CI1E24_lp0:
        Lodsb                           ; fetch 8 src pixels
        Mov     Bl,Al                   ; store here

        store_2_24bpp_pels
        store_2_24bpp_pels
        store_2_24bpp_pels
        store_2_24bpp_pels

        Loop    CI1E24_lp0              ; for all full source bytes...

        Mov     Cx,Dx                   ; fetch partial count
        Or      Cx,Cx                   ; partial pixels at end ?
        Jnz     CI1E24_Slow             ; yes -- do it slow path way...
        Ret                             ; done, 'C'=0 from Or above

;/*
;** The destination will cross a segment boundary.
;*/

CI1E24_Slow:
        test    fbPal,ITE_PAL_INDICES
        jnz     CI1E24_pal_Slow

        Mov     Dl,10000000b            ; pattern to tell us when to fetch src

CI1E24_Slow_lp0:
        Rol     Dl,1                    ; time to fetch new src byte ?
        Jnc     @F                      ; not yet...
        Lodsb                           ; fetch up to 8 src pixels
        Mov     Bl,Al                   ; cache here
@@:     Shl     Bl,1                    ; fetch next mono pixel
        Sbb     Ax,Ax                   ; replicate
        Cmp     Di,0fffdh               ; will this ovf the segment ?
        Jae     CI1E24_Slow_NextSeg     ; yes...
        Stosw                           ; store R,G
        Stosb                           ; store B
CI1E24_Slow_Reentry:
        Loop    CI1E24_Slow_lp0         ; for all src pixels...
        Clc
        Ret                             ; done

CI1E24_Slow_NextSeg:
        Stosb                           ; store R
        Or      Di,Di                   ; ovf into next segment ?
        Jnz     @F                      ; no...
        Call    GetNextSelector         ; advance to next segment
        Jc      CI1E24_Slow_NextSeg_Exit; it failed...
@@:     Stosb                           ; store R
        Or      Di,Di                   ; ovf into next segment ?
        Jnz     @F                      ; no...
        Call    GetNextSelector         ; advance to next segment
        Jc      CI1E24_Slow_NextSeg_Exit; it failed...
@@:     Stosb                           ; store R
        Or      Di,Di                   ; ovf into next segment ?
        Jnz     CI1E24_Slow_Reentry     ; no...
        Call    GetNextSelector         ; advance to next segment
        Jnc     CI1E24_Slow_Reentry     ; we got next segment, continue...
CI1E24_Slow_NextSeg_Exit:
        Ret                             ; return, 'C'=1 for error return...

;/*
;** The bits are to be returned as palette indices.  Look up the closest
;** colors to black and white and save them. Read each pel, translate it
;** and store.
;**
;** CX = number of full source bytes to transfer.
;** DX = number of pixels in partial last byte to transfer.
;*/

CI1E24_pal:
CI1E24_pal_lp0:

        Lodsb                           ; fetch 8 src pixels
        mov     dh,al                   ; store here

;/*
;** The store_2_24bpp_pal_indices macro uses registers as follows:
;**
;** AX, CX = pal indices to write for pels 1 and 2
;** BX = used as index into ColorXlate
;** DH = mono pixels to process
;** ES:DI --> destination
;*/

        push    cx
        xchg    bx,si                   ; save SI contents in BX

        store_2_24bpp_pal_indices
        store_2_24bpp_pal_indices
        store_2_24bpp_pal_indices
        store_2_24bpp_pal_indices

        xchg    bx,si                   ; restore SI
        pop     cx
        dec     cx
        jnz     CI1E24_pal_lp0          ; for all full source bytes...

        mov     cl,dl                   ; fetch partial count (CH already 0)
        Or      Cx,Cx                   ; partial pixels at end ?
        Jnz     CI1E24_pal_Slow         ; yes -- do it slow path way...

        Ret                             ; done, 'C'=0 from Or above


;/*
;** The destination will cross a segment boundary.
;*/

CI1E24_pal_Slow:
        Mov     Dl,10000000b            ; pattern to tell us when to fetch src
        mov     bx,si

CI1E24_pal_Slow_lp0:
        Rol     Dl,1                    ; time to fetch new src byte ?
        Jnc     @F                      ; not yet...
        mov     dh,[bx]                 ; fetch source byte into DH
        inc     bx                      ; point to next source byte

@@:     Shl     dh,1                    ; fetch next mono pixel
        setc    al                      ; put carry bit into AL
        cbw                             ; make it a word
        shl     ax,1                    ; make in a word index
        xchg    ax,si                   ; put into SI (next line uses [bp+si])
        mov     ax,word ptr ColorXlate[si]      ; get index value
        movzx   eax,ax                  ; extend into dword

        Cmp     Di,0fffdh               ; will this ovf the segment ?
        Jae     CI1E24_pal_Slow_NextSeg ; yes...
        Stosw                           ; store R,G
        Stosb                           ; store B
CI1E24_pal_Slow_Reentry:
        Loop    CI1E24_pal_Slow_lp0     ; for all src pixels...
        Clc
        Ret                             ; done

;/*
;** EAX = index to store
;*/

CI1E24_pal_Slow_NextSeg:
        stosb
        or      di,di
        jnz     @F
        call    GetNextSelector
        jc      CI1E24_pal_Slow_NextSeg_Exit
@@:     ror     eax,8
        stosb
        or      di,di
        jnz     @F
        call    GetNextSelector
        jc      CI1E24_pal_Slow_NextSeg_Exit
@@:     ror     eax,8
        stosb
        or      di,di
        jnz     CI1E24_pal_Slow_Reentry
        call    GetNextSelector
        jnc     CI1E24_pal_Slow_Reentry
CI1E24_pal_Slow_NextSeg_Exit:
        Ret                             ; return, 'C'=1 for error return...

CopyI1E24       Endp

        CPUMode 286

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE copy_i1e24      
;*
;* DESCRIPTION   = Internal 8 bpp pixels are copied into the external 
;*                 24 bpp RGB bitmap
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;*                 Calls:
;*                       GetNextSelector
;*
;* INPUT         = DS:SI --> source
;*                 ES:DI --> destination
;*                 CX     =  number of bytes to xlate 
;*                 'C'     =       0 if there will be no ovf across dest segments
;*                 'C'     =       1 if the dest scan crosses two user segment
;* OUTPUT        = ES:DI --> next destination byte 
;*
;* 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

CopyI8E24       Proc    Near

        Jc      CI8E24_Slow             ; destination will ovf segment bdry...

        test    fbPal,ITE_PAL_INDICES
        jnz     CI8E24_pal_indices

CI8E24_lp0:
        Lodsb                           ; fetch a src pixel
        Sub     Ah,Ah
        Shl     Ax,2                    ; turn into dword offset
        Lea     Bx,ColorXlate
        Add     Bx,Ax                   ; (better not cause carry to get set!!!)
        Mov     Ax,Ss:[Bx]              ; fetch R,G
        Stosw                           ; store R,G
        Mov     Ax,Ss:[Bx][2]           ; fetch B
        Stosb                           ; store B
        Loop    CI8E24_lp0              ; for all pixels
        Ret                             ; done, 'C'=0 from Shl above

CI8E24_pal_indices:
        Lodsb                           ; fetch a src pixel
        Sub     Ah,Ah
        stosw
        sub     al,al
        stosb
        Loop    CI8E24_pal_indices      ; for all pixels
        ret                             ; done, 'C'=0 from Sub above


;/*
;** The destination will cross a segment boundary.
;*/

CI8E24_Slow:

CI8E24_Slow_lp0:

        Lodsb                           ; fetch a src pixel
        Sub     Ah,Ah
        test    fbPal,ITE_PAL_INDICES
        jnz     @F
        Shl     Ax,2                    ; turn into dword offset
        Lea     Bx,ColorXlate
        Add     Bx,Ax
        Mov     Ax,Ss:[Bx]              ; fetch R,G
@@:
        Cmp     Di,0fffdh               ; will this RGB ovf segment ?
        Jae     CI8E24_Slow_NextSeg     ; yes...

        Stosw                           ; store R,G
        test    fbPal,ITE_PAL_INDICES
        jnz     @F
        Mov     Ax,Ss:[Bx][2]           ; fetch B
        Stosb                           ; store B
        jmp     short CI8E24_Slow_Reentry
@@:
        xor     al,al
        stosb

CI8E24_Slow_Reentry:
        Loop    CI8E24_Slow_lp0         ; for all pixels

        Clc                             ; no errors if we get here
        Ret                             ; done, 'C'=0


CI8E24_Slow_NextSeg:

        Stosb                           ; store R
        Or      Di,Di                   ; ovf to next segment ?
        Jnz     @F                      ; no...
        Call    GetNextSelector         ; advance to next segment
        Jc      CI8E24_Slow_Exit        ; it failed...
@@:

        Mov     Al,Ah                   ; fetch G
        Stosb                           ; store G
        Or      Di,Di                   ; ovf to next segment ?
        Jnz     @F                      ; no...
        Call    GetNextSelector         ; advance to next segment
        Jc      CI8E24_Slow_Exit        ; it failed...
@@:

        test    fbPal,ITE_PAL_INDICES
        jnz     @F
        Mov     Ax,Ss:[Bx][2]           ; fetch B
        Stosb                           ; store B
        jmp     short CI8E24_Slow_check_overflow
@@:
        xor     al,al
        stosb
CI8E24_Slow_check_overflow:
        Or      Di,Di                   ; ovf to next segment ?
        Jnz     CI8E24_Slow_Reentry     ; no...
        Call    GetNextSelector         ; advance to next segment
        Jnc     CI8E24_Slow_Reentry     ; succeeded...
CI8E24_Slow_Exit:
        Ret                             ; done, 'C'=1 to flag error...

CopyI8E24       Endp

page
;/***************************************************************************
;*
;* PRIVATE ROUTINE BuildFakePalette
;*
;* DESCRIPTION   = Initializes Pal2, then fill its rgb array with the first cEntries
;*                 used entries from Pal1.  If there aren't enough colors in Pal1,
;*                 fill the empty entries with the first color.
;*
;*                 Registers Preserved:
;*                       BP,ES,DS
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;**************************************************************************/

        assumes ds,nothing
        assumes ds,nothing

cProc   BuildFakePalette,<NEAR,PUBLIC,NODATA>,<>
        parmD   pPalSrc
        parmD   pPalDst
        parmW   cEntries

        localD  rgb0
cBegin

;/*
;** Load up source and destination pointers and initialize the fixed
;** size part of the destination palette.
;*/

        lds     si,pPalSrc
        assumes ds,nothing
 
        les     di,pPalDst
        assumes es,nothing

        xor     ax,ax
        mov     cx,cEntries
        stosw
        .errnz  palseg_fs
        xchg    ax,cx
        dec     cx
        stosw
        .errnz  palseg_usMax   - palseg_fs - 2
        inc     cx
        palOff  cx
        add     cx,size PALSEG
        stosw
        .errnz  palseg_cb      - palseg_usMax - 2
        .errnz  palseg_apalclr - palseg_cb    - 2

;/*
;** Take the first entry in Pal1, or take black if palette is empty.
;*/

        palSize cx,ds,si
        or      cx,cx
        jnz     bfp_fetch_first_color

        xor     ax,ax
        stosw
        stosw
        add     di,(SIZE PALCLR) - (SIZE RGB2)
        mov     word ptr rgb0.rgb2_bBlue,ax
        mov     word ptr rgb0.rgb2_bRed,ax
        dec     cEntries                ; one down
        jmp     bfp_pad_with_color_0

;/*
;** Store the first color.  Decrement the count of how many to store.
;*/

bfp_fetch_first_color:
        add     si,palseg_apalclr.palclr_rgb
        lodsw
        stosw
        xchg    ax,dx
        lodsw
        stosw
        mov     word ptr rgb0.rgb2_bBlue,dx
        mov     word ptr rgb0.rgb2_bRed,ax

        add     si,(SIZE PALCLR) - (SIZE RGB2)
        add     di,(SIZE PALCLR) - (SIZE RGB2)
        dec     cEntries                ; one down
        dec     cx
        jz      bfp_pad_with_color_0

;/*
;** Loop over the source palette collecting the rest of the needed colors.
;** If we fall through either "loop" instruction, then the source pal
;** has been exhausted and we couldn't get all the colors needed.  In
;** this case, pad out the remainder of the fake palette with the first
;** color.
;*/

bfp_next_loop:
        movsw
        movsw
        add     si,(SIZE PALCLR) - (SIZE RGB2)
        add     di,(SIZE PALCLR) - (SIZE RGB2)
        dec     cEntries
        jz      bfp_got_them_all
        loop    bfp_next_loop

;/*
;** Pad out the rest with rgb0.
;*/

bfp_pad_with_color_0:
        mov     ax,word ptr rgb0.rgb2_bBlue
        mov     dx,word ptr rgb0.rgb2_bRed
bfp_stuff_loop:
        stosw
        xchg    ax,dx
        stosw
        xchg    ax,dx
        add     di,(SIZE PALCLR) - (SIZE RGB2)
        dec     cEntries
        jnz     bfp_stuff_loop

bfp_got_them_all:
cEnd

;/***************************************************************************
;*
;* PRIVATE ROUTINE BuildFakeMonoPalette
;*
;* DESCRIPTION   = Creates a palseg data structure for a palette with two entries,
;*                 0 = black, 1 = white.
;*
;*                 Registers Preserved:      
;*                       BP,ES,DS
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;**************************************************************************/

        assumes ds,nothing
        assumes ds,nothing

cProc   BuildFakeMonoPalette,<NEAR,PUBLIC,NODATA>,<>
        parmD   pPalDst
cBegin

;/*
;** Load up source and destination pointers and initialize the fixed
;** size part of the destination palette.
;*/

        les     di,pPalDst
        assumes es,nothing

        xor     ax,ax
        mov     cx,2
        stosw
        .errnz  palseg_fs
        xchg    ax,cx
        dec     cx
        stosw
        .errnz  palseg_usMax   - palseg_fs - 2
        inc     cx
        palOff  cx
        add     cx,size PALSEG
        stosw
        .errnz  palseg_cb      - palseg_usMax - 2
        .errnz  palseg_apalclr - palseg_cb    - 2

;/*
;** Fill in the two colors.  The realization data won't be used, just the
;** colors.
;*/

        CPUMode 386
        xor     eax,eax
        stosd                   ;store black
        stosd                   ;advance ES:DI
        dec     ax
        stosw                   ;store white (B,G)
        stosb                   ;store (R)
        inc     al
        stosb                   ;store fcOptions byte
        CPUMode 286

        .errnz  palclr_rgb
        .errnz  (size PALCLR) - (size RGB2) - 4
        .errnz  rgb2_fcOptions - 3
cEnd

sEnd    Bitmap

ifdef   FIREWALLS
        public  ite_not_a_bitmap
        public  ite_its_a_Bitmap
endif
        public  ite_log_error
        public  ite_get_out
        public  ite_inv_format
        public  ite_numbers_ok
ifdef FIREWALLS
        public  ite_cbi_failed
endif
        public  ite_isnt_huge_bitmap
        public  ite_huge_bitmap
        public  ite_finish_y_calc
        public  ite_next_scan
        public  ite_in_segment
        public  ite_might_cross_seg
        public  ite_xfered_all
        public  ite_exit
        public  ite_1_have_proc
        public  ite_4_color
        public  ite_4_have_proc
        public  ite_8_color
        public  ite_8_make_color_table
        public  ite_8_have_proc
        public  ite_24_have_proc
        public  CXT_Exit
        public  CI1E1_Slow
        public  CI1E1_Slow_Exit
        public  CI8E1_lp0
        public  CI8E1_Reentry
        public  CI8E1_NextSeg
        public  CI1E4_lp0
        public  CI1E4_Reentry
        public  CI1E4_NextSeg
        public  CI8E4_lp0
        public  CI8E4_Reentry
        public  CI8E4_NextSeg
        public  CI1E8_lp0
        public  CI1E8_Reentry
        public  CI1E8_NextSeg
        public  CI8E8_Slow
        public  CI8E8_Slow_Exit
        public  CI1E24_lp0
        public  CI1E24_Slow
        public  CI1E24_Slow_lp0
        public  CI1E24_Slow_Reentry
        public  CI1E24_Slow_NextSeg
        public  CI1E24_Slow_NextSeg_Exit
        public  CI8E24_lp0
        public  CI8E24_Slow
        public  CI8E24_Slow_lp0
        public  CI8E24_Slow_Reentry
        public  CI8E24_Slow_NextSeg
        public  CI8E24_Slow_Exit
;/*
;** Procs
;*/
        public  ite_1
        public  ite_4
        public  ite_8
        public  ite_24
        public  CreateColorColorTable
        public  CreateMonoColorTable
        public  CreateXlateTable
        public  GetNextSelector
        public  CopyI1E1
        public  CopyI8E1
        public  CopyI1E4
        public  CopyI8E4
        public  CopyI1E8
        public  CopyI8E8
        public  CopyI1E24
        public  CopyI8E24
        End
