;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = PHYCOLOR.ASM
;*
;* DESCRIPTIVE NAME = Color related functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/07/87
;*
;* DESCRIPTION  Color related functions  
;*
;* FUNCTIONS    far_rgb_to_ipc
;*              rgb_to_ipc
;*              synthesize_xparent_mask
;*              synthesize_color_bits
;*              synthesize_mono_bits
;*              do_one_plane
;*              rotate_brush
;*              copy_bits_to_pattern
;*              fill_pattern_empty_bits
;*                                     
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   10/3/91:  @KY1               K. Yoshitake Fix PTR J200341/PM20                                          
;*                                (SM04960/PM20) Incorrect default pattern
;*   02/08/88                     Walt Moore [waltm] Temp kludge for the
;*                                rewrite
;*   07/13/88                     Bob Grudem [bobgru] Added special case
;*                                checking for intense black (iblk?
;*                                macro).
;*   07/19/88                     Bob Grudem [bobgru] Rewrote from scratch
;*                                to match color mapping of dithering
;*                                code.  See the discussion above for
;*                                details.
;*   07/27/88                     Bob Grudem [bobgru] Changed
;*                                packed_ipc_table so that dimmest colors
;*                                were chosen in ties instead of
;*                                brightest.  This resolves the problem of
;*                                7FBFFF (supposed to be PALEBLUE) mapping
;*                                to white, when it is used as background
;*                                for white text on the title bar!
;*                                Moreover, it does it in a consistent way
;*                                that doesn't break any of the new code.
;*   09/08/88                     Charles Whitmer [chuckwh] Changed to the
;*                                exact mapping algorithm described below.
;*                                This fixes PTR 5760 which noted that the
;*                                different mapped regions of the RGB cube
;*                                were not convex.  This is a little more
;*                                complex than the old method, and also a
;*                                little slower.  Before my change, the
;*                                MENU test in FUNTEST took 119 msec.
;*                                After my change, it takes 121.  On the
;*                                larger Random Dialogs Test, it stayed
;*                                the same at 672 msec.  So maybe we lost
;*                                2% on smaller stuff.
;*   06/21/89                     Bob Grudem [bobgru] Added the
;*                                VGA-specific code.
;*****************************************************************************/


.286p
        .xlist
        include cmacros.inc
INCL_DDIBUNDLES         equ     1
INCL_FONTFILEFORMAT     equ     1
INCL_DDIMISC            equ     1
INCL_DEV                equ     1
INCL_GRE_DEVMISC1       equ     1
INCL_GRE_FONTS          equ     1
INCL_WINSYS             equ     1
        include pmgre.inc
DINCL_CLR_TBL           equ     1
DINCL_VIO               equ     1
        include driver.inc
        include display.inc
        include fontseg.inc
        include assert.mac
        .list

        ??_out  ColorConversion

        errcode <HUGE_FONTS_NOT_SUPPORTED,INV_PATTERN_ATTR>
        errcode <INV_PATTERN_SET_ATTR,INV_PATTERN_SET_FONT>


        externFP GreEntry3


;/*
;**  The special colors which correspond to negative indices, and other
;**  public data.
;*/

TEMP_CONST equ ( ( SYSCLR_CSYSCOLORS ) - 17 ) ; This is the count of system
                                              ; colors above the 190 system
                                              ; color list.

        pubabs  MIN_SPECIAL_COLOR,%(SYSCLR_WINDOWSTATICTEXT-TEMP_CONST)
        pubabs  MIN_SYSTEM_COLOR, %(SYSCLR_WINDOWSTATICTEXT-TEMP_CONST)
        public  ctDefault
        public  adrgbIndex
        public  ipcSysClrWindow
        public  ipcSysClrWindowText
        public  drgbSysClrWindow
        public  drgbSysClrWindowText
        public  aipcSpecial
        public  adrgbSpecial
        public  adrgbDefault
        public  adDitherPatterns

;/*
;**  Equates which deal with the fixed palette and color mapping.
;**  The bits in the DRV_IPC_ equates are
;** 
;**    Bit 5  ONES_OR_ZEROS (an accelerater bit)
;**        4  MONO_BIT      (an accelerater bit)
;**        3  i  (intensity bit)
;**        2  r  (red bit)
;**        1  g  (green bit)
;**        0  b  (blue bit)
;** 
;**  ipc (internal physical color) is the name used for these throughout
;**  the driver.  Some places ipc is used to refer to the same but without
;**  the accelerator flags (i.e. exactly the bits you would read from the
;**  hardware bitplanes).  To avoid confusion I will start calling these
;**  h/w ipc's (as opposed to "driver ipc's" which have accererator bits).
;** 
;**  Note that the numeric order of DRV_IPC_XX correspondes to what is
;**  programed into the hardware palette, and NOT what is in the default
;**  color table.
;** 
;**  The IPCs_API_RGB_ equates give the corresponding API RGB value for
;**  the DRV_IPC_'s.
;*/

DRV_IPC_00      equ     00100000b       ; black
DRV_IPC_01      equ     00000001b       ; dark blue
DRV_IPC_02      equ     00000010b       ; dark green
DRV_IPC_03      equ     00000011b       ; dark turquoise
DRV_IPC_04      equ     00000100b       ; dark red
DRV_IPC_05      equ     00000101b       ; purple
DRV_IPC_06      equ     00000110b       ; mustard
DRV_IPC_07      equ     00000111b       ; gray
ifdef VGA
DRV_IPC_08      equ     00011000b       ; light gray
else
DRV_IPC_08      equ     00001000b       ; dark gray
endif
DRV_IPC_09      equ     00001001b       ; blue
DRV_IPC_10      equ     00001010b       ; green     !mono-bit!!!
DRV_IPC_11      equ     00011011b       ; turquoise (cyan)
DRV_IPC_12      equ     00001100b       ; red
DRV_IPC_13      equ     00011101b       ; pink (magenta)
DRV_IPC_14      equ     00011110b       ; yellow
DRV_IPC_15      equ     00111111b       ; white

IPCs_API_RGB_00 equ     00000000h       ; black                  00h
IPCs_API_RGB_01 equ     00000080h       ; dark blue              02h
IPCs_API_RGB_02 equ     00008000h       ; dark green             08h
IPCs_API_RGB_03 equ     00008080h       ; dark turquoise         0Ah
IPCs_API_RGB_04 equ     00800000h       ; dark red              020h
IPCs_API_RGB_05 equ     00800080h       ; purple                022h
IPCs_API_RGB_06 equ     00808000h       ; mustard               028h
IPCs_API_RGB_07 equ     00808080h       ; gray                  02Ah
ifdef VGA
IPCs_API_RGB_08 equ     00CCCCCCh       ; very light gray       015h
else
IPCs_API_RGB_08 equ     00202020h       ; dark gray             015h
endif
IPCs_API_RGB_09 equ     000000FFh       ; blue                  03h
IPCs_API_RGB_10 equ     0000FF00h       ; green                 0Ch
IPCs_API_RGB_11 equ     0000FFFFh       ; turquoise (cyan)      0Fh
IPCs_API_RGB_12 equ     00FF0000h       ; red                   030h
IPCs_API_RGB_13 equ     00FF00FFh       ; pink (magenta)        033h
IPCs_API_RGB_14 equ     00FFFF00h       ; yellow                03Ch
IPCs_API_RGB_15 equ     00FFFFFFh       ; white                 03Fh


sBegin  Data

;/*
;**  The default logical color table.  Colors 0 and 7 may be written
;**  over if SYSCLR_WINDOW or SYSCLR_WINDOWTEXT change.
;*/

ifdef VGA
        DEF_CT_INDEX08s_IPC  equ   DRV_IPC_07        ; gray
        DEF_CT_INDEX15s_IPC  equ   DRV_IPC_08        ; light gray (vga)
        DEF_CT_INDEX08s_RGB  equ   IPCs_API_RGB_07   ; gray
        DEF_CT_INDEX15s_RGB  equ   IPCs_API_RGB_08   ; light gray (vga)
else
        DEF_CT_INDEX08s_IPC  equ   DRV_IPC_08        ; dark gray (ega)
        DEF_CT_INDEX15s_IPC  equ   DRV_IPC_07        ; gray
        DEF_CT_INDEX08s_RGB  equ   IPCs_API_RGB_08   ; dark gray (ega)
        DEF_CT_INDEX15s_RGB  equ   IPCs_API_RGB_07   ; gray
endif

ctDefault       label   word

        dw      CT_IDENT
        dw      adrgbDefault
        dw      0                               ;Never saved/restored
        dw      0                               ;Minimum loaded index
        dw      DEFAULT_COLOR_TABLE_SIZE-1      ;Maximum loaded color

;/*
;**  The actual physical colors
;*/

        .errnz  ($-ctDefault)-ct_aipc
        dw      DRV_IPC_15              ;00 white         SYSCLR_WINDOW
        dw      DRV_IPC_09              ;01 blue
        dw      DRV_IPC_12              ;02 red
        dw      DRV_IPC_13              ;03 pink (magenta)
        dw      DRV_IPC_10              ;04 green
        dw      DRV_IPC_11              ;05 turquoise (cyan)
        dw      DRV_IPC_14              ;06 yellow
        dw      DRV_IPC_00              ;07 black         SYSCLR_WINDOWTEXT
        dw      DEF_CT_INDEX08s_IPC     ;08 darker gray
        dw      DRV_IPC_01              ;09 dark blue
        dw      DRV_IPC_04              ;10 dark red
        dw      DRV_IPC_05              ;11 purple
        dw      DRV_IPC_02              ;12 dark green
        dw      DRV_IPC_03              ;13 dark turquoise
        dw      DRV_IPC_06              ;14 mustard
        dw      DEF_CT_INDEX15s_IPC     ;15 lighter gray

;/*
;**  The rgb triplets for those physical colors
;**  changes here must be reflected in adDitherPattern
;*/

adrgbDefault    label   byte
        dd      IPCs_API_RGB_15      ; white         SYSCLR_WINDOW
        dd      IPCs_API_RGB_09      ; blue
        dd      IPCs_API_RGB_12      ; red
        dd      IPCs_API_RGB_13      ; pink (magenta)
        dd      IPCs_API_RGB_10      ; green
        dd      IPCs_API_RGB_11      ; turquoise (cyan)
        dd      IPCs_API_RGB_14      ; yellow
        dd      IPCs_API_RGB_00      ; black         SYSCLR_WINDOWTEXT
        dd      DEF_CT_INDEX08s_RGB  ; darker gray
        dd      IPCs_API_RGB_01      ; dark blue
        dd      IPCs_API_RGB_04      ; dark red
        dd      IPCs_API_RGB_05      ; purple
        dd      IPCs_API_RGB_02      ; dark green
        dd      IPCs_API_RGB_03      ; dark turquoise
        dd      IPCs_API_RGB_06      ; mustard
        dd      DEF_CT_INDEX15s_RGB  ; lighter gray

sEnd Data

sBegin Code
;/*
;**  These are fast lookup dither patterns for the above default colors
;*/

even

adDitherPatterns label   dword
            ;IIRRGGBB
        dd  0FFFFFFFFh ; white
        dd  0FF0000FFh ; blue
        dd  0FFFF0000h ; red
        dd  0FFFF00FFh ; pink (magenta)
        dd  0FF00FF00h ; green
        dd  0FF00FFFFh ; turquoise (cyan)
        dd  0FFFFFF00h ; yellow
        dd  000000000h ; black
        dd  000FFFFFFh ; dark gray
        dd  0000000FFh ; dark blue
        dd  000FF0000h ; dark red
        dd  000FF00FFh ; purple
        dd  00000FF00h ; dark green
        dd  00000FFFFh ; dark turquoise
        dd  000FFFF00h ; mustard
        dd  0FF000000h ; gray

sEnd Code

sBegin Data


;/*
;**  A sorted list of the RGB colors for mapping from an index
;*/

adrgbIndex      equ     this dword
        dd      IPCs_API_RGB_00
        dd      IPCs_API_RGB_01
        dd      IPCs_API_RGB_02
        dd      IPCs_API_RGB_03
        dd      IPCs_API_RGB_04
        dd      IPCs_API_RGB_05
        dd      IPCs_API_RGB_06
        dd      IPCs_API_RGB_07
        dd      IPCs_API_RGB_08
        dd      IPCs_API_RGB_09
        dd      IPCs_API_RGB_10
        dd      IPCs_API_RGB_11
        dd      IPCs_API_RGB_12
        dd      IPCs_API_RGB_13
        dd      IPCs_API_RGB_14
        dd      IPCs_API_RGB_15


;/*
;**  The system colors (driver) ipc table.
;*/

aipcSpecial     equ     this word

        rept TEMP_CONST
        dw      0
        endm

        dw      DRV_IPC_09              ;-26            WINDOWSTATICTEXT
        dw      DEF_CT_INDEX08s_IPC     ;-25            SCROLLBAR
        dw      DRV_IPC_11              ;-24            BACKGROUND
        dw      DRV_IPC_09              ;-23            ACTIVETITLE
        dw      DRV_IPC_15              ;-22            INACTIVETITLE
        dw      DRV_IPC_11              ;-21            MENU
ipcSysClrWindow equ     this word
        dw      DRV_IPC_15              ;-20            WINDOW
        dw      DRV_IPC_00              ;-19            WINDOWFRAME
        dw      DRV_IPC_00              ;-18            MENUTEXT
ipcSysClrWindowText equ this word
        dw      DRV_IPC_00              ;-17            WINDOWTEXT
        dw      DRV_IPC_15              ;-16            TITLETEXT
        dw      DEF_CT_INDEX15s_IPC     ;-15            ACTIVEBORDER
        dw      DEF_CT_INDEX15s_IPC     ;-14            INACTIVEBORDER
        dw      DRV_IPC_03              ;-13            APPWORKSPACE
        dw      DRV_IPC_09              ;-12            HELPBACKGROUND
        dw      DRV_IPC_11              ;-11            HELPTEXT
        dw      DRV_IPC_15              ;-10            HELPHILITE
        .errnz  SYSCLR_CSYSCOLORS - ($ - aipcSpecial) / 2
        dw      INVALID_IPC             ;-9
        dw      INVALID_IPC             ;-8
        dw      INVALID_IPC             ;-7
        dw      INVALID_IPC             ;-6
        dw      DRV_IPC_00              ;-5             All 0s
        dw      DRV_IPC_15              ;-4             All 1s
        dw      INVALID_IPC             ;-3
        dw      DRV_IPC_15              ;-2             White
        dw      DRV_IPC_00              ;-1             Black

;/*
;** The rgb triplets corresponding to the system colors
;*/

adrgbSpecial    equ     this dword

        rept TEMP_CONST
        dd      0
        endm


        dd      000000FFh               ;-26            WINDOWSTATICTEXT
ifdef VGA
        dd      00CCCCCCh               ;-25            SCROLLBAR
else
        dd      003F3F3Fh               ;-25            SCROLLBAR
endif
        dd      0000FFFFh               ;-24            BACKGROUND
        dd      000000FFh               ;-23            ACTIVETITLE
        dd      00FFFFFFh               ;-22            INACTIVETITLE
        dd      0000FFFFh               ;-21            MENU
drgbSysClrWindow equ    this dword
        dd      00FFFFFFh               ;-20            WINDOW
        dd      00000000h               ;-19            WINDOWFRAME
        dd      00000000h               ;-18            MENUTEXT
drgbSysClrWindowText equ this dword
        dd      00000000h               ;-17            WINDOWTEXT
        dd      00FFFFFFh               ;-16            TITLETEXT
        dd      007F7F7Fh               ;-15            ACTIVEBORDER
        dd      007F7F7Fh               ;-14            INACTIVEBORDER
        dd      00007FFFh               ;-13            APPWORKSPACE
        dd      000000FFh               ;-12            HELPBACKGROUND
        dd      0000FFFFh               ;-11            HELPTEXT
        dd      00FFFFFFh               ;-10            HELPHILITE
        .errnz  SYSCLR_CSYSCOLORS - ($ - adrgbSpecial) / 4
        dd      -1                      ;-9
        dd      -1                      ;-8
        dd      -1                      ;-7
        dd      -1                      ;-6
        dd      IPCs_API_RGB_00         ;-5             All 0s
        dd      IPCs_API_RGB_15         ;-4             All 1s
        dd      -1                      ;-3
        dd      IPCs_API_RGB_15         ;-2             White
        dd      IPCs_API_RGB_00         ;-1             Black

;/*
;**  ipc_index_mask created to make merging with other drivers easier (other
;**  drivers use the variable, not the constant).
;*/
        globalW ipc_index_mask,15       ;Lower 4 bits of IPC are color index

sEnd    Data

sBegin  Bitmap
        assumes cs,Bitmap

        public  aipcLookup              ; used in pixel.asm
aipcLookup      equ     this word
        dw      DRV_IPC_00
        dw      DRV_IPC_01
        dw      DRV_IPC_02
        dw      DRV_IPC_03
        dw      DRV_IPC_04
        dw      DRV_IPC_05
        dw      DRV_IPC_06
        dw      DRV_IPC_07
        dw      DRV_IPC_08
        dw      DRV_IPC_09
        dw      DRV_IPC_10
        dw      DRV_IPC_11
        dw      DRV_IPC_12
        dw      DRV_IPC_13
        dw      DRV_IPC_14
        dw      DRV_IPC_15

sEnd    Bitmap

sBegin  Code
        assumes cs,Code

        externW CodeData


;/***************************************************************************
;*
;* FUNCTION NAME = rgb_to_ipc 
;*
;* DESCRIPTION   = rgb_to_ipc accepts a logical RGB color value and returns 
;*                 the device dependent, physical representation of bits    
;*                 necessary to display the color closest to the specified  
;*                 color on the device.                                     
;*                                                                          
;*                 Registers Preserved:                                                             
;*                       BX,CX,SI,DI,DS,ES                                                          
;*                 Registers Destroyed:                                                             
;*                       DX                                                                         
;*                                                                          
;* INPUT         = DX:AX = RGB color (AL=blue, AH=green, DL=red)  
;*                                                                          
;* OUTPUT        = AL              = physical color index         
;*                 AL:C0           = blue  intensity msb                                                                   
;*                 AL:C1           = green intensity msb                                                                   
;*                 AL:C2           = red   intensity msb                                                                   
;*                 AL:C3           = intensity                                                                             
;*                 AL:MONO_BIT     = 0 if BX < BWThreshold                                                                 
;*                                 = 1 if BX >= BWThreshold                                                                
;*                 AL:ONES_OR_ZEROS= 1 if bits are 1111 or 0000                                                            
;*                 Sign bit clear (AX)                                                                                     
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

;/*
;**  Exact Mapping Algorithm                                               
;**                                                                        
;**  The previous algorithm, which we used to do color mapping, divided    
;**  the RGB cube into 729 tiny cubes, and then looked up the result in    
;**  a table.  (A very cleverly coded table, I might add.)                 
;**  Unfortunately, this means that the regions of the RGB cube that       
;**  map to each palette color are not necessarily convex.  This is        
;**  bad.  An app can follow a straight line through the RGB cube and      
;**  have it go in and out of the same palette color several times!        
;**                                                                        
;**  What I do here is map the given color to the nearest palette color,   
;**  where nearest is meant in a Euclidean sense.  I.e. I find the         
;**  palette color that minimizes (dR)^2 + (dG)^2 + (dB)^2.                
;**                                                                        
;**  The result of analyzing the RGB cube this way is that there are 16    
;**  regions bounded by several planes.  Since there is a 6-fold           
;**  symmetry to this mapping problem, I assume that the color indices     
;**  are in a decreasing order.  I.e. I have 3 indices, c1 c2 and c3,      
;**  such that:                                                            
;**                                                                        
;**      FF >= c1 >= c2 >= c3 >= 0.                                        
;**                                                                        
;**  This restricts us to a tetrahedron with 1/6th the volume of the       
;**  cube. There are only 8 palette colors in this tetrahedron as follows: 
;**                                                                        
;**      EGA:                      VGA:                                    
;**      ----                      ----                                    
;**      0:  (00,00,00)            0:  (00,00,00)                          
;**      1:  (20,20,20)            1:  (CC,CC,CC)                          
;**      2:  (80,00,00)            2:  (80,00,00)                          
;**      3:  (FF,00,00)            3:  (FF,00,00)                          
;**      4:  (80,80,00)            4:  (80,80,00)                          
;**      5:  (80,80,80)            5:  (80,80,80)                          
;**      6:  (FF,FF,00)            6:  (FF,FF,00)                          
;**      7:  (FF,FF,FF)            7:  (FF,FF,FF)                          
;**                                                                        
;**  Given the ordering restriction there are only 13 relevant             
;**  conditions that separate the color regions.  They are:                
;**                                                                        
;**  EGA:                                                                  
;**  ----                                                                  
;**      c1 +   c2 +   c3 <  30h      (0:1)                                
;**      c1 +   c2 +   c3 <  F0h      (1:5)                                
;**    3 c1 + 3 c2 -   c3 < 1D0h      (1:4)                                
;**    3 c1 -   c2 -   c3 <  D0h      (1:2)                                
;**             c2        <  40h      (2:4)                                
;**      c1               <  C0h      (2:3)                                
;**      c1 -   c2        <  80h      (4:3)                                
;**                    c3 <  40h      (4:5)                                
;**      c1 +   c2        < 180h      (4:6)                                
;**      c1 -   c2 -   c3 <  40h      (5:3)                                
;**      c1 +   c2 -   c3 < 140h      (5:6)                                
;**      c1 +   c2 +   c3 < 240h      (5:7)                                
;**                    c3 <  80h      (6:7)                                
;**                                                                        
;**  VGA:                                                                  
;**  ----                                                                  
;**      c1               <  40h      (0:2)                                
;**      c1 +   c2 - 4 c3 <  32h      (1:6)                                
;**      c1 +   c2 +   c3 < 2AFh      (1:7)                                
;**      c1               <  C0h      (2:3)                                
;**             c2        <  40h      (2:4)                                
;**             c2        <  80h      (3:6)                                
;**      c1 -   c2        <  80h      (4:3)                                
;**                    c3 <  40h      (4:5)                                
;**      c1 +   c2        < 180h      (4:6)                                
;**      c1 +   c2 +   c3 < 1F2h      (5:1)                                
;**      c1 +   c2 -   c3 < 140h      (5:6)                                
;**      c1 -   c2 -   c3 <  40h      (5:3)                                
;**                    c3 <  80h      (6:7)                                
;**                                                                        
;**  I have identified each condition with (n:m).  The given condition     
;**  must be true if the color is to be mapped to n.  It must be false     
;**  for the color to be mapped to m.  For example, we must have:          
;**                                                                        
;**     (2:4) AND (2:3) AND NOT (1:2)                                      
;**                                                                        
;**  if a given color is to be mapped into color 2.                        
;**                                                                        
;**  The boundary of EGA region 1 is the most complex.  Things are         
;**  simplified if we shrink this region a tiny bit by redefining          
;**  (1:2).  Hopefully no one will even notice this.  This change also     
;**  makes (1:5) and (1:4) useless. The simplified list of planes is       
;**  therefore:                                                            
;**                                                                        
;**      c1           <  40h      (1:2)'                                   
;**      c1           <  C0h      (2:3)                                    
;**           c2      <  40h      (2:4)                                    
;**                c3 <  40h      (4:5)                                    
;**                c3 <  80h      (6:7)                                    
;**      c1 + c2      < 180h      (4:6)                                    
;**      c1 + c2 + c3 <  30h      (0:1)                                    
;**      c1 + c2 + c3 < 240h      (5:7)                                    
;**      c1 + c2 - c3 < 140h      (5:6)                                    
;**      c1 - c2      <  80h      (4:3)                                    
;**      c1 - c2 - c3 <  40h      (5:3)                                    
;**                                                                        
;**  To determine the region we are in, we'll perform all 11 tests and     
;**  pack the true/false values into a word.  We'll then examine the       
;**  word for the requirements for each region.                            
;**                                                                        
;**  For the VGA, we'll perform all 13 tests and otherwise act like        
;**  the EGA.                                                              
;*/

ifdef VGA

;/*
;**  The following 8 words show which of the 11 conditions must be true
;**  for the given color to map into each region.  Note that I have taken
;**  the n value from each (n:m) in order.  The bit in the nth word below
;**  it is on.
;*/

rgb_true_map    equ     this word
        dw      1000000000000b  ; 0
        dw      0000000010100b  ; 1
        dw      0110000000000b  ; 2
        dw      0001000000000b  ; 3
        dw      0000101000010b  ; 4
        dw      0000000101001b  ; 5
        dw      0000010000000b  ; 6
        dw      0000000000000b  ; 7

;/*
;** The following 8 words show which of the 11 conditions we depend on
;** for the given color to map into each region.  If a bit is on here,
;** it means that we have a requirement for it to be true or false.  If
;** the corresponding bit is on in rgb_true_map, we require the
;** condition to be true.  Otherwise we require it to be false.
;** If the bit is not on in rgb_needed_map, then the given region doesn't
;** care about that test.
;** Note that I have taken the n and m values from each (n:m) in order.
;** The bits in the nth and mth words below them are on.
;*/

rgb_needed_map  equ     this word
        dw      1000000000000b  ; 0
        dw      0000000110100b  ; 1
        dw      1110000000000b  ; 2
        dw      0101000000011b  ; 3
        dw      0010101000010b  ; 4
        dw      0000100101001b  ; 5
        dw      0001011001100b  ; 6
        dw      0000010010000b  ; 7

else ;!VGA

;/*
;**  The following 8 words show which of the 11 conditions must be true
;**  for the given color to map into each region.  Note that I have taken
;**  the n value from each (n:m) in order.  The bit in the nth word below
;**  it is on.
;*/

rgb_true_map    equ     this word
        dw      00000010000b    ; 0
        dw      10000000000b    ; 1
        dw      01100000000b    ; 2
        dw      00000000000b    ; 3
        dw      00010100010b    ; 4
        dw      00000001101b    ; 5
        dw      00001000000b    ; 6
        dw      00000000000b    ; 7

;/*
;** The following 8 words show which of the 11 conditions we depend on
;** for the given color to map into each region.  If a bit is on here,
;** it means that we have a requirement for it to be true or false.  If
;** the corresponding bit is on in rgb_true_map, we require the
;** condition to be true.  Otherwise we require it to be false.
;** If the bit is not on in rgb_needed_map, then the given region doesn't
;** care about that test.
;** Note that I have taken the n and m values from each (n:m) in order.
;** The bits in the nth and mth words below them are on.
;*/

rgb_needed_map  equ     this word
        dw      00000010000b    ; 0
        dw      10000010000b    ; 1
        dw      11100000000b    ; 2
        dw      01000000011b    ; 3
        dw      00110100010b    ; 4
        dw      00010001101b    ; 5
        dw      00001100100b    ; 6
        dw      00001001000b    ; 7
endif ;!VGA

;/*
;** Once we have decided which of the 8 colors to map to from the sorted
;** RGB value, we need to unsort the index and pick up the accelerator bits
;** at the same time.  (There's probably a neat macroized way to do this,
;** but it seemed just as easy to enter the table manually.)
;**
;** I start by listing what IRGB value we should return for each of the 8
;** sorted colors and 6 permutations.  I do it in binary so that its
;** correctness can be easily checked.
;**
;**                                     Permutation Number
;**         color      \       0     1     2     3     4     5     6     7
;**        indices      \     BGR    -    BRG   GRB   GBR   RBG    -    RGB
;** -------------------------------------------------------------------------
;** 0:  (00,00,00)   0000 |  0000b   -   0000b 0000b 0000b 0000b   -   0000b
;** 1:  (20,20,20)   1000 |  1000b   -   1000b 1000b 1000b 1000b   -   1000b
;** 2:  (80,00,00)   0100 |  0001b   -   0010b 0010b 0001b 0100b   -   0100b
;** 3:  (FF,00,00)   1100 |  1001b   -   1010b 1010b 1001b 1100b   -   1100b
;** 4:  (80,80,00)   0110 |  0011b   -   0011b 0110b 0101b 0101b   -   0110b
;** 5:  (80,80,80)   0111 |  0111b   -   0111b 0111b 0111b 0111b   -   0111b
;** 6:  (FF,FF,00)   1110 |  1011b   -   1011b 1110b 1101b 1101b   -   1110b
;** 7:  (FF,FF,FF)   1111 |  1111b   -   1111b 1111b 1111b 1111b   -   1111b
;**
;** And now the same table in decimal:
;**
;** 0:  (00,00,00)   0000 |    00    -     00    00    00    00    -     00
;** 1:  (20,20,20)   1000 |    08    -     08    08    08    08    -     08
;** 2:  (80,00,00)   0100 |    01    -     02    02    01    04    -     04
;** 3:  (FF,00,00)   1100 |    09    -     10    10    09    12    -     12
;** 4:  (80,80,00)   0110 |    03    -     03    06    05    05    -     06
;** 5:  (80,80,80)   0111 |    07    -     07    07    07    07    -     07
;** 6:  (FF,FF,00)   1110 |    11    -     11    14    13    13    -     14
;** 7:  (FF,FF,FF)   1111 |    15    -     15    15    15    15    -     15
;*/

;/*
;** And now the real thing with accelerators attached!
;*/

aipcColorAndPerm        equ     this byte
        db      DRV_IPC_00,-1,DRV_IPC_00,DRV_IPC_00,\
                 DRV_IPC_00,DRV_IPC_00,-1,DRV_IPC_00
        db      DRV_IPC_08,-1,DRV_IPC_08,DRV_IPC_08,\
                 DRV_IPC_08,DRV_IPC_08,-1,DRV_IPC_08
        db      DRV_IPC_01,-1,DRV_IPC_02,DRV_IPC_02,\
                 DRV_IPC_01,DRV_IPC_04,-1,DRV_IPC_04
        db      DRV_IPC_09,-1,DRV_IPC_10,DRV_IPC_10,\
                 DRV_IPC_09,DRV_IPC_12,-1,DRV_IPC_12
        db      DRV_IPC_03,-1,DRV_IPC_03,DRV_IPC_06,\
                 DRV_IPC_05,DRV_IPC_05,-1,DRV_IPC_06
        db      DRV_IPC_07,-1,DRV_IPC_07,DRV_IPC_07,\
                 DRV_IPC_07,DRV_IPC_07,-1,DRV_IPC_07
        db      DRV_IPC_11,-1,DRV_IPC_11,DRV_IPC_14,\
                 DRV_IPC_13,DRV_IPC_13,-1,DRV_IPC_14
        db      DRV_IPC_15,-1,DRV_IPC_15,DRV_IPC_15,\
                 DRV_IPC_15,DRV_IPC_15,-1,DRV_IPC_15

;/***************************************************************************
;*
;* FUNCTION NAME = far_rgb_to_ipc
;*
;* DESCRIPTION   = Calls rgb_to_ipc
;*                                                                          
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   far_rgb_to_ipc,<FAR,PUBLIC,NODATA,NONWIN>
cBegin
        call    rgb_to_ipc
cEnd

cProc   rgb_to_ipc,<NEAR,PUBLIC>,<bx,cx,si,di>
cBegin

;/*
;**  Sort the color indices to get c1 >= c2 >= c3.
;**  DL = c1, AH = c2, AL = c3.
;*/

        xor     si,si
        cmp     ah,dl                   ; CF on if c2 < c1
        adc     si,si
        cmp     al,ah                   ; CF on if c3 < c2
        adc     si,si
        cmp     al,dl                   ; CF on if c3 < c1
        adc     si,si                   ; SI = permutation number
        mov     bx,si
        add     bx,bx
        add     bx,CodeOFFSET rgb_sort
        jmp     bx
rgb_sort:
        xchg    ah,al                   ; 123 -> 132
        xchg    al,al                   ;   (NOP)
        xchg    dl,al                   ; 132 -> 231
        xchg    ah,al                   ; 231 -> 213
        xchg    dl,al                   ; 213 -> 312
        xchg    ah,al                   ; 312 -> 321  done!
        xchg    al,al                   ;   (NOP)
        .errnz  ($ - rgb_sort) - 14

;/*
;** Calculate the 11 conditions
;*/

        xor     bx,bx
        xchg    bl,ah                   ; AX = c3, BX = c2
        xor     dh,dh                   ; DX = c1
        xor     di,di                   ; DI = condition flags

ifdef VGA
        cmp     dl,40h                  ; c1 < 40h
        adc     di,di

        cmp     dl,0C0h                 ; c1 < C0h
        adc     di,di

        cmp     bl,40h                  ; c2 < 40h
        adc     di,di

        cmp     bl,80h                  ; c2 < 80h
        adc     di,di

        cmp     al,40h                  ; c3 < 40h
        adc     di,di

        cmp     al,80h
        adc     di,di                   ; c3 < 80h

        mov     cx,dx
        add     cx,bx                   ; CX = c1 + c2
        cmp     cx,180h                 ; c1 + c2 < 180h
        adc     di,di

        add     cx,ax                   ; CX = c1 + c2 + c3
        cmp     cx,1F2h                 ; c1 + c2 + c3 < 1F2h
        adc     di,di

        cmp     cx,2AFh                 ; c1 + c2 + c3 < 2AFh
        adc     di,di

        sub     cx,ax
        sub     cx,ax
        cmp     cx,140h                 ; c1 + c2 - c3 < 140h
        adc     di,di

        sub     cx,ax
        sub     cx,ax
        sub     cx,ax
        add     cx,200h
        cmp     cx,232h                 ; c1 + c2 - 4*c3 < 32h
        adc     di,di

        mov     cx,dx
        sub     cx,bx                   ; CX = c1 - c2
        cmp     cx,80h                  ; c1 - c2 < 80h
        adc     di,di

        sub     cx,ax
        add     cx,100h                 ; CX = c1 - c2 - c3 + 100h, which is > 0
        cmp     cx,140h                 ; c1 - c2 - c3 < 40h
        adc     di,di

else ;!VGA
        cmp     dl,40h                  ; c1 < 40h
        adc     di,di

        cmp     dl,0C0h                 ; c1 < C0h
        adc     di,di

        cmp     bl,40h                  ; c2 < 40h
        adc     di,di

        cmp     al,40h                  ; c3 < 40h
        adc     di,di

        cmp     al,80h                  ; c3 < 80h
        adc     di,di

        mov     cx,dx
        add     cx,bx                   ; CX = c1 + c2
        cmp     cx,180h                 ; c1 + c2 < 180h
        adc     di,di

        add     cx,ax                   ; CX = c1 + c2 + c3
        cmp     cx,30h                  ; c1 + c2 + c3 < 30h
        adc     di,di

        cmp     cx,240h                 ; c1 + c2 + c3 < 240h
        adc     di,di

        sub     cx,ax
        sub     cx,ax
        cmp     cx,140h                 ; c1 + c2 - c3 < 140h
        adc     di,di

        mov     cx,dx
        sub     cx,bx                   ; CX = c1 - c2
        cmp     cx,80h                  ; c1 - c2 < 80h
        adc     di,di

        sub     cx,ax
        add     cx,100h                 ; CX = c1 - c2 - c3 + 100h, which is > 0
        cmp     cx,140h                 ; c1 - c2 - c3 < 40h
        adc     di,di
endif ;!VGA

;/*
;**  Now check the conditions against the requirements for each of the
;**  8 regions.  We first invert all bits which we require to be true,
;**  and then make sure that all needed bits are off.
;*/

        mov     bx,-2
rgb_region_loop:
        inc     bx
        inc     bx
        mov     cx,rgb_true_map[bx]     ; turn off the TRUE guys
        xor     cx,di
        and     cx,rgb_needed_map[bx]   ; Check that all TRUEs and FALSEs
        jnz     rgb_region_loop         ;   are really off.

;/*
;** Now turn the color number and permutation into an ipc with accelerators.
;*/

        shl     bx,2
        add     bx,si                   ; BX = 8 * color + permutation
        mov     al,aipcColorAndPerm[bx]
        xor     ah,ah
cEnd


S_HATCH_BR1_0   equ     0FFh and 01110111b      ;Solid Hatched brush 1
S_HATCH_BR1_1   equ     0FFh and 11111111b
S_HATCH_BR1_2   equ     0FFh and 11111111b
S_HATCH_BR1_3   equ     0FFh and 11111111b
S_HATCH_BR1_4   equ     0FFh and 11011101b
S_HATCH_BR1_5   equ     0FFh and 11111111b
S_HATCH_BR1_6   equ     0FFh and 11111111b
S_HATCH_BR1_7   equ     0FFh and 11111111b

S_HATCH_BR2_0   equ     0FFh and 01110111b      ;Solid Hatched brush 2
S_HATCH_BR2_1   equ     0FFh and 11111111b
S_HATCH_BR2_2   equ     0FFh and 11011101b
S_HATCH_BR2_3   equ     0FFh and 11111111b
S_HATCH_BR2_4   equ     0FFh and 01110111b
S_HATCH_BR2_5   equ     0FFh and 11111111b
S_HATCH_BR2_6   equ     0FFh and 11011101b
S_HATCH_BR2_7   equ     0FFh and 11111111b

S_HATCH_BR3_0   equ     0FFh and 01110111b      ;Solid Hatched brush 3
S_HATCH_BR3_1   equ     0FFh and 11011101b
S_HATCH_BR3_2   equ     0FFh and 01110111b
S_HATCH_BR3_3   equ     0FFh and 11011101b
S_HATCH_BR3_4   equ     0FFh and 01110111b
S_HATCH_BR3_5   equ     0FFh and 11011101b
S_HATCH_BR3_6   equ     0FFh and 01110111b
S_HATCH_BR3_7   equ     0FFh and 11011101b

S_HATCH_BR4_0   equ     0FFh and 01110111b      ;Solid Hatched brush 4
S_HATCH_BR4_1   equ     0FFh and 10101010b
S_HATCH_BR4_2   equ     0FFh and 11011101b
S_HATCH_BR4_3   equ     0FFh and 10101010b
S_HATCH_BR4_4   equ     0FFh and 01110111b
S_HATCH_BR4_5   equ     0FFh and 10101010b
S_HATCH_BR4_6   equ     0FFh and 11011101b
S_HATCH_BR4_7   equ     0FFh and 10101010b

S_HATCH_BR5_0   equ     0FFh and 10101010b      ;Solid Hatched brush 5
S_HATCH_BR5_1   equ     0FFh and 01010101b
S_HATCH_BR5_2   equ     0FFh and 10101010b
S_HATCH_BR5_3   equ     0FFh and 01010101b
S_HATCH_BR5_4   equ     0FFh and 10101010b
S_HATCH_BR5_5   equ     0FFh and 01010101b
S_HATCH_BR5_6   equ     0FFh and 10101010b
S_HATCH_BR5_7   equ     0FFh and 01010101b

S_HATCH_BR6_0   equ     0FFh and not S_HATCH_BR4_0      ;Solid Hatched brush 6
S_HATCH_BR6_1   equ     0FFh and not S_HATCH_BR4_1
S_HATCH_BR6_2   equ     0FFh and not S_HATCH_BR4_2
S_HATCH_BR6_3   equ     0FFh and not S_HATCH_BR4_3
S_HATCH_BR6_4   equ     0FFh and not S_HATCH_BR4_4
S_HATCH_BR6_5   equ     0FFh and not S_HATCH_BR4_5
S_HATCH_BR6_6   equ     0FFh and not S_HATCH_BR4_6
S_HATCH_BR6_7   equ     0FFh and not S_HATCH_BR4_7

S_HATCH_BR7_0   equ     0FFh and not S_HATCH_BR3_0      ;Solid Hatched brush 7
S_HATCH_BR7_1   equ     0FFh and not S_HATCH_BR3_1
S_HATCH_BR7_2   equ     0FFh and not S_HATCH_BR3_2
S_HATCH_BR7_3   equ     0FFh and not S_HATCH_BR3_3
S_HATCH_BR7_4   equ     0FFh and not S_HATCH_BR3_4
S_HATCH_BR7_5   equ     0FFh and not S_HATCH_BR3_5
S_HATCH_BR7_6   equ     0FFh and not S_HATCH_BR3_6
S_HATCH_BR7_7   equ     0FFh and not S_HATCH_BR3_7

S_HATCH_BR8_0   equ     0FFh and not S_HATCH_BR2_0      ;Solid Hatched brush 8
S_HATCH_BR8_1   equ     0FFh and not S_HATCH_BR2_1
S_HATCH_BR8_2   equ     0FFh and not S_HATCH_BR2_2
S_HATCH_BR8_3   equ     0FFh and not S_HATCH_BR2_3
S_HATCH_BR8_4   equ     0FFh and not S_HATCH_BR2_4
S_HATCH_BR8_5   equ     0FFh and not S_HATCH_BR2_5
S_HATCH_BR8_6   equ     0FFh and not S_HATCH_BR2_6
S_HATCH_BR8_7   equ     0FFh and not S_HATCH_BR2_7

NS_HATCH_BR_0   equ     0FFh and 00000000b      ;No Shading Hatched brush
NS_HATCH_BR_1   equ     0FFh and 00000000b
NS_HATCH_BR_2   equ     0FFh and 00000000b
NS_HATCH_BR_3   equ     0FFh and 00000000b
NS_HATCH_BR_4   equ     0FFh and 00000000b
NS_HATCH_BR_5   equ     0FFh and 00000000b
NS_HATCH_BR_6   equ     0FFh and 00000000b
NS_HATCH_BR_7   equ     0FFh and 00000000b

A_HATCH_BR_0    equ     0FFh and not S_HATCH_BR5_0      ;Alternating Hatched brush
A_HATCH_BR_1    equ     0FFh and not S_HATCH_BR5_1
A_HATCH_BR_2    equ     0FFh and not S_HATCH_BR5_2
A_HATCH_BR_3    equ     0FFh and not S_HATCH_BR5_3
A_HATCH_BR_4    equ     0FFh and not S_HATCH_BR5_4
A_HATCH_BR_5    equ     0FFh and not S_HATCH_BR5_5
A_HATCH_BR_6    equ     0FFh and not S_HATCH_BR5_6
A_HATCH_BR_7    equ     0FFh and not S_HATCH_BR5_7

H_HATCH_BR_0    equ     0FFh and 11111111b      ;Horizontal Hatched brush colors
H_HATCH_BR_1    equ     0FFh and 00000000b
H_HATCH_BR_2    equ     0FFh and 00000000b
H_HATCH_BR_3    equ     0FFh and 00000000b
H_HATCH_BR_4    equ     0FFh and 11111111b
H_HATCH_BR_5    equ     0FFh and 00000000b
H_HATCH_BR_6    equ     0FFh and 00000000b
H_HATCH_BR_7    equ     0FFh and 00000000b

V_HATCH_BR_0    equ     0FFh and 10001000b      ;Vertical Hatched brush colors
V_HATCH_BR_1    equ     0FFh and 10001000b
V_HATCH_BR_2    equ     0FFh and 10001000b
V_HATCH_BR_3    equ     0FFh and 10001000b
V_HATCH_BR_4    equ     0FFh and 10001000b
V_HATCH_BR_5    equ     0FFh and 10001000b
V_HATCH_BR_6    equ     0FFh and 10001000b
V_HATCH_BR_7    equ     0FFh and 10001000b

HV_HATCH_BR_0   equ     H_HATCH_BR_0 or V_HATCH_BR_0   ; Cross hatch
HV_HATCH_BR_1   equ     H_HATCH_BR_1 or V_HATCH_BR_1
HV_HATCH_BR_2   equ     H_HATCH_BR_2 or V_HATCH_BR_2
HV_HATCH_BR_3   equ     H_HATCH_BR_3 or V_HATCH_BR_3
HV_HATCH_BR_4   equ     H_HATCH_BR_4 or V_HATCH_BR_4
HV_HATCH_BR_5   equ     H_HATCH_BR_5 or V_HATCH_BR_5
HV_HATCH_BR_6   equ     H_HATCH_BR_6 or V_HATCH_BR_6
HV_HATCH_BR_7   equ     H_HATCH_BR_7 or V_HATCH_BR_7

if      1                                                       ;@KY1

DB_HATCH_BR1_0  equ     0FFh and 00000001b      ;\ diagonal hatched brush 1
DB_HATCH_BR1_1  equ     0FFh and 10000000b
DB_HATCH_BR1_2  equ     0FFh and 01000000b
DB_HATCH_BR1_3  equ     0FFh and 00100000b
DB_HATCH_BR1_4  equ     0FFh and 00010000b
DB_HATCH_BR1_5  equ     0FFh and 00001000b
DB_HATCH_BR1_6  equ     0FFh and 00000100b
DB_HATCH_BR1_7  equ     0FFh and 00000010b

DB_HATCH_BR2_0  equ     0FFh and 10000001b      ;\ diagonal hatched brush 2
DB_HATCH_BR2_1  equ     0FFh and 01100000b
DB_HATCH_BR2_2  equ     0FFh and 00011000b
DB_HATCH_BR2_3  equ     0FFh and 00000110b
DB_HATCH_BR2_4  equ     0FFh and 10000001b
DB_HATCH_BR2_5  equ     0FFh and 01100000b
DB_HATCH_BR2_6  equ     0FFh and 00011000b
DB_HATCH_BR2_7  equ     0FFh and 00000110b

DF_HATCH_BR1_0  equ     0FFh and 10000000b      ;/ diagonal hatched brush 1
DF_HATCH_BR1_1  equ     0FFh and 00000001b
DF_HATCH_BR1_2  equ     0FFh and 00000010b
DF_HATCH_BR1_3  equ     0FFh and 00000100b
DF_HATCH_BR1_4  equ     0FFh and 00001000b
DF_HATCH_BR1_5  equ     0FFh and 00010000b
DF_HATCH_BR1_6  equ     0FFh and 00100000b
DF_HATCH_BR1_7  equ     0FFh and 01000000b

DF_HATCH_BR2_0  equ     0FFh and 10000001b      ;/ diagonal hatched brush 2
DF_HATCH_BR2_1  equ     0FFh and 00000110b
DF_HATCH_BR2_2  equ     0FFh and 00011000b
DF_HATCH_BR2_3  equ     0FFh and 01100000b
DF_HATCH_BR2_4  equ     0FFh and 10000001b
DF_HATCH_BR2_5  equ     0FFh and 00000110b
DF_HATCH_BR2_6  equ     0FFh and 00011000b
DF_HATCH_BR2_7  equ     0FFh and 01100000b

else                                                            ;@KY1

DB_HATCH_BR1_0  equ     0FFh and 00010001b      ;\ diagonal hatched brush 1
DB_HATCH_BR1_1  equ     0FFh and 10001000b
DB_HATCH_BR1_2  equ     0FFh and 01000100b
DB_HATCH_BR1_3  equ     0FFh and 00100010b
DB_HATCH_BR1_4  equ     0FFh and 00010001b
DB_HATCH_BR1_5  equ     0FFh and 10001000b
DB_HATCH_BR1_6  equ     0FFh and 01000100b
DB_HATCH_BR1_7  equ     0FFh and 00100010b

DB_HATCH_BR2_0  equ     0FFh and 10000001b      ;\ diagonal hatched brush 2
DB_HATCH_BR2_1  equ     0FFh and 01100000b
DB_HATCH_BR2_2  equ     0FFh and 00011000b
DB_HATCH_BR2_3  equ     0FFh and 00000110b
DB_HATCH_BR2_4  equ     0FFh and 10000001b
DB_HATCH_BR2_5  equ     0FFh and 01100000b
DB_HATCH_BR2_6  equ     0FFh and 00011000b
DB_HATCH_BR2_7  equ     0FFh and 00000110b

DF_HATCH_BR1_0  equ     0FFh and 10001000b      ;/ diagonal hatched brush 1
DF_HATCH_BR1_1  equ     0FFh and 00010001b
DF_HATCH_BR1_2  equ     0FFh and 00100010b
DF_HATCH_BR1_3  equ     0FFh and 01000100b
DF_HATCH_BR1_4  equ     0FFh and 10001000b
DF_HATCH_BR1_5  equ     0FFh and 00010001b
DF_HATCH_BR1_6  equ     0FFh and 00100010b
DF_HATCH_BR1_7  equ     0FFh and 01000100b

DF_HATCH_BR2_0  equ     0FFh and 10000001b      ;/ diagonal hatched brush 2
DF_HATCH_BR2_1  equ     0FFh and 00000110b
DF_HATCH_BR2_2  equ     0FFh and 00011000b
DF_HATCH_BR2_3  equ     0FFh and 01100000b
DF_HATCH_BR2_4  equ     0FFh and 10000001b
DF_HATCH_BR2_5  equ     0FFh and 00000110b
DF_HATCH_BR2_6  equ     0FFh and 00011000b
DF_HATCH_BR2_7  equ     0FFh and 01100000b

endif                                                           ;@KY1

DBF_HATCH_BR_0  equ     DF_HATCH_BR1_1 or DB_HATCH_BR1_0  ; Diagonal cross hatch
DBF_HATCH_BR_1  equ     DF_HATCH_BR1_2 or DB_HATCH_BR1_1
DBF_HATCH_BR_2  equ     DF_HATCH_BR1_3 or DB_HATCH_BR1_2
DBF_HATCH_BR_3  equ     DF_HATCH_BR1_4 or DB_HATCH_BR1_3
DBF_HATCH_BR_4  equ     DF_HATCH_BR1_5 or DB_HATCH_BR1_4
DBF_HATCH_BR_5  equ     DF_HATCH_BR1_6 or DB_HATCH_BR1_5
DBF_HATCH_BR_6  equ     DF_HATCH_BR1_7 or DB_HATCH_BR1_6
DBF_HATCH_BR_7  equ     DF_HATCH_BR1_0 or DB_HATCH_BR1_7


                public  abBasePatterns
abBasePatterns  label   byte            ; used in mkvalid.asm

        db      S_HATCH_BR1_0, S_HATCH_BR1_1, S_HATCH_BR1_2, S_HATCH_BR1_3
        db      S_HATCH_BR1_4, S_HATCH_BR1_5, S_HATCH_BR1_6, S_HATCH_BR1_7
        db      S_HATCH_BR2_0, S_HATCH_BR2_1, S_HATCH_BR2_2, S_HATCH_BR2_3
        db      S_HATCH_BR2_4, S_HATCH_BR2_5, S_HATCH_BR2_6, S_HATCH_BR2_7
        db      S_HATCH_BR3_0, S_HATCH_BR3_1, S_HATCH_BR3_2, S_HATCH_BR3_3
        db      S_HATCH_BR3_4, S_HATCH_BR3_5, S_HATCH_BR3_6, S_HATCH_BR3_7
        db      S_HATCH_BR4_0, S_HATCH_BR4_1, S_HATCH_BR4_2, S_HATCH_BR4_3
        db      S_HATCH_BR4_4, S_HATCH_BR4_5, S_HATCH_BR4_6, S_HATCH_BR4_7
        db      S_HATCH_BR5_0, S_HATCH_BR5_1, S_HATCH_BR5_2, S_HATCH_BR5_3
        db      S_HATCH_BR5_4, S_HATCH_BR5_5, S_HATCH_BR5_6, S_HATCH_BR5_7
        db      S_HATCH_BR6_0, S_HATCH_BR6_1, S_HATCH_BR6_2, S_HATCH_BR6_3
        db      S_HATCH_BR6_4, S_HATCH_BR6_5, S_HATCH_BR6_6, S_HATCH_BR6_7
        db      S_HATCH_BR7_0, S_HATCH_BR7_1, S_HATCH_BR7_2, S_HATCH_BR7_3
        db      S_HATCH_BR7_4, S_HATCH_BR7_5, S_HATCH_BR7_6, S_HATCH_BR7_7
        db      S_HATCH_BR8_0, S_HATCH_BR8_1, S_HATCH_BR8_2, S_HATCH_BR8_3
        db      S_HATCH_BR8_4, S_HATCH_BR8_5, S_HATCH_BR8_6, S_HATCH_BR8_7
        db      V_HATCH_BR_0,  V_HATCH_BR_1,  V_HATCH_BR_2,  V_HATCH_BR_3
        db      V_HATCH_BR_4,  V_HATCH_BR_5,  V_HATCH_BR_6,  V_HATCH_BR_7
        db      H_HATCH_BR_0,  H_HATCH_BR_1,  H_HATCH_BR_2,  H_HATCH_BR_3
        db      H_HATCH_BR_4,  H_HATCH_BR_5,  H_HATCH_BR_6,  H_HATCH_BR_7
        db      DF_HATCH_BR1_0,DF_HATCH_BR1_1,DF_HATCH_BR1_2,DF_HATCH_BR1_3
        db      DF_HATCH_BR1_4,DF_HATCH_BR1_5,DF_HATCH_BR1_6,DF_HATCH_BR1_7
        db      DF_HATCH_BR2_0,DF_HATCH_BR2_1,DF_HATCH_BR2_2,DF_HATCH_BR2_3
        db      DF_HATCH_BR2_4,DF_HATCH_BR2_5,DF_HATCH_BR2_6,DF_HATCH_BR2_7
        db      DB_HATCH_BR1_0,DB_HATCH_BR1_1,DB_HATCH_BR1_2,DB_HATCH_BR1_3
        db      DB_HATCH_BR1_4,DB_HATCH_BR1_5,DB_HATCH_BR1_6,DB_HATCH_BR1_7
        db      DB_HATCH_BR2_0,DB_HATCH_BR2_1,DB_HATCH_BR2_2,DB_HATCH_BR2_3
        db      DB_HATCH_BR2_4,DB_HATCH_BR2_5,DB_HATCH_BR2_6,DB_HATCH_BR2_7
        db      NS_HATCH_BR_0, NS_HATCH_BR_1, NS_HATCH_BR_2, NS_HATCH_BR_3
        db      NS_HATCH_BR_4, NS_HATCH_BR_5, NS_HATCH_BR_6, NS_HATCH_BR_7
        db      0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh
        db      A_HATCH_BR_0,  A_HATCH_BR_1,  A_HATCH_BR_2,  A_HATCH_BR_3
        db      A_HATCH_BR_4,  A_HATCH_BR_5,  A_HATCH_BR_6,  A_HATCH_BR_7
        db      HV_HATCH_BR_0, HV_HATCH_BR_1, HV_HATCH_BR_2, HV_HATCH_BR_3
        db      HV_HATCH_BR_4, HV_HATCH_BR_5, HV_HATCH_BR_6, HV_HATCH_BR_7
        db      DBF_HATCH_BR_0,DBF_HATCH_BR_1,DBF_HATCH_BR_2,DBF_HATCH_BR_3
        db      DBF_HATCH_BR_4,DBF_HATCH_BR_5,DBF_HATCH_BR_6,DBF_HATCH_BR_7


;/***************************************************************************
;*
;* FUNCTION NAME = synthesize_xparent_mask 
;*
;* DESCRIPTION   = The transparency mask will be synthsized from the color  
;*                 portion of the given brush.                              
;*                                                                          
;*                 Registers Preserved:                                                                 
;*                       SI,BP,DS                                                                       
;*                 Registers Destroyed:                                                                 
;*                       AX,BX,CX,DX,DI,FLAGS                                                           
;*                                                                          
;* INPUT         = DS:SI --> DDC to use
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   synthesize_xparent_mask,<NEAR,PUBLIC>
cBegin

;/*
;**  All colors which match the background color will be set to 0 in the
;**  transparency mask.  All other colors will be set to 1 in the mask.
;*/

        mov     al,[si].ddc_pa.pa_ba.ba_ipcBack
        shr     al,1                    ;Isolate the four colors
        sbb     dl,dl                   
        shr     al,1                               
        sbb     dh,dh                   ;C1 color
        shr     al,1
        sbb     bl,bl                   ;C2 color
        shr     al,1
        sbb     bh,bh                   ;C3 color

;/*
;**  We now have color masks for each plane. What we'll do is XOR each
;**  plane of a byte with the given color.  This will give 0 where it
;**  is the color, and 1 where it isn't.  We'll OR the results of this
;**  to give a 1 wherever the color didn't match the background.  This
;**  is then give us our transparency mask.
;*/


        mov     cx,SIZE_PATTERN

sfc_loop:
        mov     al,[si].ddc_pa.pa_abColor[SIZE_PATTERN*0]
        mov     ah,[si].ddc_pa.pa_abColor[SIZE_PATTERN*1]
        xor     ax,dx
        xchg    ax,di
        mov     al,[si].ddc_pa.pa_abColor[SIZE_PATTERN*2]
        mov     ah,[si].ddc_pa.pa_abColor[SIZE_PATTERN*3]
        xor     ax,bx
        or      ax,di
        or      al,ah
        mov     [si].ddc_pa.pa_abMask,al
        inc     si
        loop    sfc_loop
        sub     si,SIZE_PATTERN
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = synthesize_color_bits
;*
;* DESCRIPTION   = The color bits will be synthesized from the transparency 
;*                 mask of the given brush.  The PA_GRAY accelerator is set 
;*                 if the ONES_OR_ZEROS accelerator is set in both the      
;*                 foreground and background colors, since it would mean the
;*                 colors were either black or white.                       
;*                                                                          
;*                 Registers Preserved:                                                                
;*                       SI,BP,DS                                                                      
;*                 Registers Destroyed:                                                                
;*                       AX,BX,CX,DX,DI,FLAGS                                                          
;*                 Calls:
;*                       DoOnePlane
;*                                                                          
;* INPUT         = DS:SI --> DDC to use 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   synthesize_color_bits,<NEAR,PUBLIC>
cBegin

        lea     di,[si].ddc_pa.pa_abColor       ;--> destination
        mov     dl,[si].ddc_pa.pa_ba.ba_ipc
        mov     dh,[si].ddc_pa.pa_ba.ba_ipcBack
        mov     al,dl
        and     al,dh
        test    al,ONES_OR_ZEROS
        jz      scb_process_bits
        or      [si].ddc_pa.pa_fb,PA_GRAY
scb_process_bits:
        call    do_one_plane                    ;Some .errnzs in here
        call    do_one_plane
        call    do_one_plane
        call    do_one_plane
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = mono_brush_from_mask
;*
;* DESCRIPTION   = The mono bits will be synthesized from the transparency
;*                 mask of the given brush.                                 
;*                                                                          
;*                 Registers Preserved:                                                                
;*                       SI,BP,DS                                                                      
;*                 Registers Destroyed:                                                                
;*                       AX,BX,CX,DX,DI,FLAGS                                                          
;*                 Calls:
;*                       DoOnePlane
;*                                                                          
;* INPUT         = DS:SI --> DDC to use
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   synthesize_mono_bits,<NEAR,PUBLIC>
cBegin

        lea     di,[si].ddc_pa.pa_abMono        ;--> destination
        mov     dl,[si].ddc_pa.pa_ba.ba_ipc
        mov     dh,[si].ddc_pa.pa_ba.ba_ipcBack
        shr     dx,4
        .errnz  MONO_BIT - 00010000b
        call    do_one_plane
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DoOnePlane 
;*
;* DESCRIPTION   = One plane of a brush is synthesized. 
;*                 
;*                 Registers Preserved:
;*                       SI,BP,DS      
;*                 Registers Destroyed:
;*                       AX,BX,CX,FLAGS
;*                 Calls:
;*                       DoOnePlane
;*
;* INPUT         = DS:SI --> DDC to use
;*                 DS:DI --> Destination to use
;*                 DL     =  Foreground IPC
;*                 DH     =  Background IPC
;*
;* OUTPUT        = DI  =  DI + SIZE_PATTERN
;*                 DL  =  Foreground IPC SHR 1 
;*                 DH  =  background IPC SHR 1 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

mono_conversions label  word

        dw      00000h                  ;00 - background = 0, foreground = 0
        dw      000FFh                  ;01 - background = 0, foreground = 1
        dw      0FFFFh                  ;10 - background = 1, foreground = 0
        dw      0FF00h                  ;11 - background = 1, foreground = 1

cProc   do_one_plane,<NEAR,PUBLIC>
cBegin
        xor     bx,bx
        shr     dh,1
        rcl     bx,1
        shr     dl,1
        rcl     bx,1
        add     bx,bx                   ;Indexing into words
        mov     bx,mono_conversions[bx]
        mov     cx,SIZE_PATTERN

do_one_plane_loop:
        mov     al,[si].ddc_pa.pa_abMask
        and     al,bl
        xor     al,bh
        mov     [di],al
        inc     di
        inc     si
        loop    do_one_plane_loop
        sub     si,SIZE_PATTERN
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = rotate_brush     
;*
;* DESCRIPTION   = The brush is rotated right the given amount.             
;*
;*                 Registers Preserved: 
;*                       DI,SI,BP,DS    
;*                 Registers Destroyed: 
;*                       AX,CX,FLAGS    
;*
;* INPUT         = DS:SI --> DDC to use
;*                 CL   =  Amount to rotate right
;*
;* OUTPUT        = DS:SI --> DDC to use
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   rotate_brush,<NEAR,PUBLIC>
cBegin
        mov     bx,6                     
        lea     di,[si].ddc_pa.pa_abColor

rb_loop:
        ror     byte ptr [di][0],cl      
        ror     byte ptr [di][1],cl
        ror     byte ptr [di][2],cl
        ror     byte ptr [di][3],cl
        ror     byte ptr [di][4],cl
        ror     byte ptr [di][5],cl
        ror     byte ptr [di][6],cl
        ror     byte ptr [di][7],cl
        add     di,SIZE_PATTERN
        dec     bx
        jnz     rb_loop
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = copy_bits_to_pattern 
;*
;* DESCRIPTION   = Copys the specified bits to a pattern for a DDC
;*                 
;*                  Registers Preserved:        
;*                        BX,BP,DS              
;*                  Registers Destroyed:        
;*                        AX,CX,DX,SI,DI,FLAGS  
;*
;* INPUT         = AL   =  Number of color planes in source bitmap                 
;*                 AH   =  Width of bitmap (numbers only significant up through 8) 
;*                 DS:BX --> DDC
;*                 CX   =  Number of bytes per scan of source bitmap              
;*                 DX   =  Height of bitmap                                       
;*                 DS:SI --> Destination of bits (first BYTE of pattern bits buffer)
;*                 ES:DI --> Source bits (first BYTE of bits buffer)
;*                 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

;/*
;** This function is public only for debugging.
;*/

cProc   copy_bits_to_pattern,<PUBLIC,NEAR,NODATA>,<>

        localB  SrcWidth        ;width in pels of source
        localW  SrcHeight       ;height in scans of source
        localW  ScanIncr        ;increment to next scan of source
        localW  PlaneIncr       ;increment to next color plane of source
        localB  PlaneCnt        ;number of color planes in source
        localB  InitScanCnt     ;number of scans to copy per plane of source
        localB  ScanCnt         ;loop counter
        localB  BitFillCnt      ;number of empty bits per scan in pattern
        localB  ScanFillCnt     ;number of empty scans in pattern
        localB  BackClr         ;our version of the background color

cBegin
        push    bx              ;save DDC

        mov     PlaneCnt,al     ;save number color planes for loop counter
        mov     SrcWidth,ah     ;save input to make space for calculations
        mov     PlaneIncr,cx    ;plane increment always bytes-per-scan
        mov     SrcHeight,dx    ;need this a few times


;/*
;**  Compute the increment to get to the next scanline of the source (the
;**  destination increment is always -1).  The increment to the next plane
;**  is pa_cbScan (the width of a source scan in bytes), since the color
;**  planes are interleaved.  This means that the next scan is found beyond
;**  all the color planes of the current scan.  Color bitmaps are always
;**  four planes deep.
;*/

        xchg    ax,cx           ;get bytes-per-scan into AX, plane cnt in CL
        neg     ax              ;walking up from lower left, so...
        shr     cl,1            ;CL = 2 if color, = 0 if mono
        shl     ax,cl           ;ScanIncr *= 4 if color, unchanged if mono
        .errnz  BITS_PEL - 4
        mov     ScanIncr,ax     ;save the chef d'oeuvre
        neg     ax              ;want it positive to alter initial DI
        dec     dx              ;want bottom scan line
        mul     dx              ;AX --> offset bottom scan line
        add     di,ax           ;save new improved source pointer
        add     si,SIZE_PATTERN - 1 ;point to end of first plane of destination


;/*
;**  Create an ipc (internal physical color) to use when padding empty
;**  bits with the background color.  If the source is color, take the
;**  background color as is.  If the source is monochrome, then background
;**  color bits are written as 0, which Bitblt knows to translate into the
;**  the current pattern background color.
;*/


        mov     bl,[bx].ddc_pa.pa_ba.ba_ipcBack.ipc_bClr
        cmp     PlaneCnt,2      ;C = 1 if mono source
        sbb     bh,bh           ;BH = 0FFh if mono source, =   0  if color
        not     bh              ;BH =   0  if mono source, = 0FFh if color
        and     bl,bh           ;background color forced to 0 if mono source
        mov     BackClr,bl      ;save background color bits


;/*
;**  Determine whether or not the source has enough scans to fill the
;**  destination buffer (it needs 8).  Save the number of scans which
;**  need to be padded with the background color.  Save the inner loop
;**  limit in InitScanCnt.
;*/

        mov     ax,PATTERN_HEIGHT  ;InitScanCnt = min(8, SrcHeight)
        usmin_ax   SrcHeight
        mov     InitScanCnt,al     ;save inner loop limit
        neg     al                 ;ScanFillCnt = 8 - ScanCnt
        add     al,PATTERN_HEIGHT  ; 
        mov     ScanFillCnt,al     ;save for updating DDC, and doing the fill


;/*
;**  Determine whether or not the source has enough bits to fill an entire
;**  scan of the destination buffer (it needs 8).  Save the number of bits
;**  which need to be padded with the background color, and create a mask
;**  to clear them out of a byte.  Load up some registers which won't
;**  change during the loop.
;*/


        mov     ah,0FFh            ;assume no unused bits to mask off
        mov     cl,PATTERN_WIDTH-1 ;destination will be 8 bits wide
        sub     cl,SrcWidth        ;CL = no. bits to fill w/bk color (-1)
        sbb     ch,ch              ;CH = 0FFh if no need to rotate mask, else 0
        not     ch                 ;CH =   0  if ..., else 0FFH
        inc     cl                 ;in case CL positive, we want to add 1
        and     cl,ch              ;CL = 0 if was negative, else unchanged
        mov     BitFillCnt,cl      ;save for updating DDC
        shl     ah,cl              ;make mask where used bits are 1's
        xor     ch,ch              ;loop invariant, so do it here
        mov     dx,ScanIncr        ;source scan increment, loop invariant


;/*
;**  Copy one plane of the source bitmap into the pattern attributes
;**  structure.  The color masks (AH, BL, BH) need to be computed,
;**  and the number of scans to copy initialized.  If after copying
;**  the whole plane there weren't enough scans to fill the destination
;**  buffer, pad out the rest with the background color.
;*/


cbp_copy_plane:
        push    di              ;save pointer to source bits
        mov     al,InitScanCnt  ;initialize number of scans to copy
        mov     ScanCnt,al      ; 
        shr     BackClr,1       ;shift current color bit into carry
        sbb     bl,bl           ;BL = 0 if color = 0; BL = 0FFh if color = 1
        mov     bh,bl           ;make copy in case unused scans to fill
        not     ah              ;make mask where unused bits are 1's
        and     bl,ah           ;mask off used bits
        not     ah              ;restore mask of used bits
        mov     cl,ScanCnt

cbp_copy_scan:
        mov     al,es:[di]      ;get source byte
        and     al,ah           ;clear off unused bits
        or      al,bl           ;fill unused bits with background color
        mov     [si],al         ;store byte
        dec     si              ;adjust destination pointer
        add     di,dx           ;adjust source pointer to next scan
        loop    cbp_copy_scan

        mov     al,ScanFillCnt  ;how many scans to fill w/bk color?
        or      al,al           ;if none,
        jz      cbp_next_plane  ;  do the next color plane
cbp_fill_extra_scan:
        mov     [si],bh         ;store scan of background color
        dec     si              ;point to next destination scan
        dec     al              ;one less scan to fill
        jnz     cbp_fill_extra_scan

cbp_next_plane:
        pop     di              ;restore pointer to source bits
        add     di,PlaneIncr    ;point to next color plane
        add     si,SIZE_PATTERN * 2
        dec     PlaneCnt
        jnz     cbp_copy_plane


;/*
;**  Get the DDC back and store the number of empty bits per scan and
;**  the number of empty scans.  The next time the background color
;**  changes, if the brush source was a color bitmap, these empty bits
;**  will need to be filled with the new background color.
;*/

        pop     bx              ;restore DDC
        mov     al,BitFillCnt
        mov     [bx].ddc_pa.pa_cxFill,al
        mov     al,ScanFillCnt
        mov     [bx].ddc_pa.pa_cyFill,al

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = fill_pattern_empty_bits
;*
;* DESCRIPTION   = Use the background color to fill in those color pattern   
;*                 bits not taken from a color source bitmap.  This          
;*                 subroutine will only be called when the following are     
;*                 true:  The pattern bits came from a color bitmap not large
;*                 enough to fill 8x8 pels.  The pattern background color    
;*                 changed so that the brush bits were invalidated.  The     
;*                 display driver fills in the empty space in the pattern    
;*                 with the current pattern background color.  When the      
;*                 background color changes, these bits need to be updated.  
;*                 The monochrome bits and transparency mask will be         
;*                 synthesized from the color bits after this subroutine is  
;*                 done.                                                     
;*                                                                           
;*                  Registers Preserved:                                                            
;*                        SI,DI,BP,DS                                                               
;*                  Registers Destroyed:                                                            
;*                        AX,BX,CX,DX,ES                                                            
;*                                                                           
;* INPUT         = DS:SI --> DDC
;* OUTPUT        = direction flag cleared 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   fill_pattern_empty_bits,<PUBLIC,NEAR,NODATA>,<si,di>
        localW  ScanAdj
cBegin
        cld                             ;lodsb/stosb need this

        mov     bl,BITS_PEL             ;number of planes to loop over
        mov     bh,bl                   ;save for second half of subroutine
        mov     dl,[si].ddc_pa.pa_cyFill;get number of scans to fill
        xor     dh,dh                   ;make a word
        mov     ScanAdj,dx              ;save for second half of subroutine
        or      dx,dx                   ;if no scans to fill
        jz      fpeb_chk_cxfill         ;  check for bits on the right side


;/*
;** Fill in top cyFill scans with background color.
;*/

        mov     ah,[si].ddc_pa.pa_ba.ba_ipcBack.ipc_bClr
        mov     cx,ds
        mov     es,cx
        assumes es,Data                 ;want ES:DI --> first scan to fill
        lea     di,[si].ddc_pa.pa_abColor
@@:
        shr     ah,1                    ;put color bit in carry flag
        sbb     al,al                   ;AL = 0FFh if color was 1
        mov     cx,dx                   ;reload scan count
        rep     stosb                   ;stuff background color
        add     di,SIZE_PATTERN         ;point into next color plane
        sub     di,dx                   ;point back to beginning of plane
        dec     bl                      ;count down number of planes
        jnz     @B


fpeb_chk_cxfill:
        mov     cl,[si].ddc_pa.pa_cxFill;get number of bits to fill
        or      cl,cl                   ;if no bits to fill
        jz      fpeb_exit               ;  leave the subroutine


;/*
;** Fill in least significant cxFill bits with background color.
;*/

        mov     ax,0FFh                 ;assume no bits to alter
        shl     ax,cl                   ;AND-mask for right side bits
        mov     cl,al                   ;save it in CL
        mov     dh,8                    ;want DH = 8-cyFill
        sub     dh,[si].ddc_pa.pa_cyFill
        cmp     dh,8                    ;do we have to do all 8 scans?
        jne     fpeb_es_ok              ;if not, ES = DS by code up above
        mov     ax,ds                   ;if yes, we'd better set up ES now
        mov     es,ax
        assumes es,Data                 ;want ES:DI --> first scan to fill
fpeb_es_ok:
        mov     ah,[si].ddc_pa.pa_ba.ba_ipcBack.ipc_bClr
        lea     si,[si].ddc_pa.pa_abColor
        add     si,ScanAdj              ;DS:SI = ES:DI --> first byte to
        mov     di,si                   ;  update
        mov     bl,bh                   ;number of planes to loop over
fpeb_loop_top:
        shr     ah,1                    ;put color bit in carry flag
        sbb     ch,ch                   ;CH = 0FFh if color was 1
        not     cl                      ;CL = mask of bits to alter
        and     ch,cl                   ;CH = XOR mask
        not     cl                      ;CL = bits to preserve (AND mask)
        mov     dl,dh                   ;reload scan count
@@:
        lodsb                           ;get pattern byte
        and     al,cl                   ;and off background color to black
        xor     al,ch                   ;xor it to the correct color
        stosb                           ;store it back in pattern
        dec     dl                      ;count down the scans to alter
        jnz     @B
        add     si,ScanAdj              ;point to first byte in next plane
        mov     di,si
        dec     bl                      ;count down the color planes
        jnz     fpeb_loop_top

fpeb_exit:
cEnd

sEnd
end
