;*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     55,132
        TITLE    Physical Colors
        SUBTITLE Header

;/*****************************************************************************
;*
;* SOURCE FILE NAME = PHYCOLOR.ASM
;*
;* DESCRIPTIVE NAME = Color related functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/08/91
;*
;* DESCRIPTION  Color related functions  
;*              
;* FUNCTIONS    DoOnePlane
;*              rgb_to_ipc
;*              synthesize_xparent_mask
;*              synthesize_color_bits
;*              synthesize_mono_bits 
;*              rotate_brush 
;*              copy_bits_to_pattern 
;*              fill_pattern_empty_bits
;*              alloc_brush
;*              free_brush 
;*              copy_brush 
;*              check_brush 
;*                                     
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*
;*****************************************************************************/

        .386P
        .MODEL FLAT,SYSCALL

;/*
;** Included files
;*/

INCL_GPIPRIMITIVES EQU 1
INCL_NOBASEAPI     EQU 1
INCL_NOCOMMON      EQU 1
INCL_SAADEFS       EQU 1
INCL_WINSYS        EQU 1
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP       EQU 1
DINCL_CLR_TBL      EQU 1
DINCL_ENABLE       EQU 1
        INCLUDE DRIVER.INC
DIN_PHYCOLOR       EQU 1
        INCLUDE EXTERN.INC
        INCLUDE DISPLAY.INC
        INCLUDE PROTOS.INC
;/*
;** Equates
;*/

ifdef FIREWALLS
BRUSH_VALUE EQU 01010101h
check_brush PROTO SYSCALL,
        pBrush:DWORD
endif

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

.ERRNZ MIN_SPECIAL_COLOR - MIN_SYSTEM_COLOR
.ERRNZ MIN_SPECIAL_COLOR - SYSCLR_SHADOWHILITEBGND

;/*
;** Equates which deal with the fixed palette and color mapping.  The bits in
;** the DRV_IPC_ equates are:
;**
;**   Bit 5  ONES_OR_ZEROS (an accelerator bit)
;**       4  MONO_BIT      (an accelerator 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.  In 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 corresponds 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.
;*/

;              IIRRGGBB
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
DRV_IPC_08 EQU 00011000b        ; light gray
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
IPCs_API_RGB_08 EQU 00CCCCCCh   ; very light gray       015h
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

;/*
;** The following equates define the various brush patterns.
;*/

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                                                      

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

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

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)

;/*
;** Data
;*/

        .DATA
DEFINED_ELSEWHERE EQU 1
PUBLIC ctDefault
ctDefault LABEL DWORD

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

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

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

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

        ALIGN   4

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

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

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

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

adrgbIndex LABEL DWORD
        DWORD   IPCs_API_RGB_00
        DWORD   IPCs_API_RGB_01
        DWORD   IPCs_API_RGB_02
        DWORD   IPCs_API_RGB_03
        DWORD   IPCs_API_RGB_04
        DWORD   IPCs_API_RGB_05
        DWORD   IPCs_API_RGB_06
        DWORD   IPCs_API_RGB_07
        DWORD   IPCs_API_RGB_08
        DWORD   IPCs_API_RGB_09
        DWORD   IPCs_API_RGB_10
        DWORD   IPCs_API_RGB_11
        DWORD   IPCs_API_RGB_12
        DWORD   IPCs_API_RGB_13
        DWORD   IPCs_API_RGB_14
        DWORD   IPCs_API_RGB_15

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

aipcSpecial LABEL WORD

      REPEAT    TEMP_CONST
        WORD    0
      ENDM

        WORD    DRV_IPC_09              ; -26           WINDOWSTATICTEXT
        WORD    DEF_CT_INDEX08s_IPC     ; -25           SCROLLBAR
        WORD    DRV_IPC_11              ; -24           BACKGROUND
        WORD    DRV_IPC_09              ; -23           ACTIVETITLE
        WORD    DRV_IPC_15              ; -22           INACTIVETITLE
        WORD    DRV_IPC_11              ; -21           MENU

ipcSysClrWindow LABEL WORD
        WORD    DRV_IPC_15              ; -20           WINDOW
        WORD    DRV_IPC_00              ; -19           WINDOWFRAME
        WORD    DRV_IPC_00              ; -18           MENUTEXT

ipcSysClrWindowText LABEL WORD
        WORD    DRV_IPC_00              ; -17           WINDOWTEXT
        WORD    DRV_IPC_15              ; -16           TITLETEXT
        WORD    DEF_CT_INDEX15s_IPC     ; -15           ACTIVEBORDER
        WORD    DEF_CT_INDEX15s_IPC     ; -14           INACTIVEBORDER
        WORD    DRV_IPC_03              ; -13           APPWORKSPACE
        WORD    DRV_IPC_09              ; -12           HELPBACKGROUND
        WORD    DRV_IPC_11              ; -11           HELPTEXT
        WORD    DRV_IPC_15              ; -10           HELPHILITE
        .ERRNZ  SYSCLR_CSYSCOLORS - ($ - aipcSpecial) / 2
        WORD    INVALID_IPC             ; -9
        WORD    INVALID_IPC             ; -8
        WORD    INVALID_IPC             ; -7
        WORD    INVALID_IPC             ; -6
        WORD    DRV_IPC_00              ; -5            All 0s
        WORD    DRV_IPC_15              ; -4            All 1s
        WORD    INVALID_IPC             ; -3
        WORD    DRV_IPC_15              ; -2            White
        WORD    DRV_IPC_00              ; -1            Black

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

        ALIGN  4

adrgbSpecial LABEL DWORD

      REPEAT    TEMP_CONST
        DWORD   0
      ENDM

        DWORD   000000FFh       ; -26           WINDOWSTATICTEXT
        DWORD   00CCCCCCh       ; -25           SCROLLBAR
        DWORD   0000FFFFh       ; -24           BACKGROUND
        DWORD   000000FFh       ; -23           ACTIVETITLE
        DWORD   00FFFFFFh       ; -22           INACTIVETITLE
        DWORD   0000FFFFh       ; -21           MENU
        .ERRNZ  drgbSysClrWindow-adrgbSpecial-(TEMP_CONST+6)*(sizeof DWORD)

drgbSysClrWindow LABEL DWORD
        DWORD   00FFFFFFh       ; -20           WINDOW
        DWORD   00000000h       ; -19           WINDOWFRAME
        DWORD   00000000h       ; -18           MENUTEXT
        .ERRNZ  drgbSysClrWindowText-drgbSysClrWindow-3*(sizeof DWORD)

drgbSysClrWindowText LABEL DWORD
        DWORD   00000000h       ; -17           WINDOWTEXT
        DWORD   00FFFFFFh       ; -16           TITLETEXT
        DWORD   007F7F7Fh       ; -15           ACTIVEBORDER
        DWORD   007F7F7Fh       ; -14           INACTIVEBORDER
        DWORD   00007FFFh       ; -13           APPWORKSPACE
        DWORD   000000FFh       ; -12           HELPBACKGROUND
        DWORD   0000FFFFh       ; -11           HELPTEXT
        DWORD   00FFFFFFh       ; -10           HELPHILITE
        .ERRNZ  SYSCLR_CSYSCOLORS - ($ - adrgbSpecial) / 4
        DWORD   -1              ; -9
        DWORD   -1              ; -8
        DWORD   -1              ; -7
        DWORD   -1              ; -6
        DWORD   IPCs_API_RGB_00 ; -5            All 0s
        DWORD   IPCs_API_RGB_15 ; -4            All 1s
        DWORD   -1              ; -3
        DWORD   IPCs_API_RGB_15 ; -2            White
        DWORD   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).
;*/

ipc_index_mask DWORD 15 ; Lower 4 bits of IPC are color index

        ALIGN  4

aipcLookup LABEL WORD
        WORD    DRV_IPC_00
        WORD    DRV_IPC_01
        WORD    DRV_IPC_02
        WORD    DRV_IPC_03
        WORD    DRV_IPC_04
        WORD    DRV_IPC_05
        WORD    DRV_IPC_06
        WORD    DRV_IPC_07
        WORD    DRV_IPC_08
        WORD    DRV_IPC_09
        WORD    DRV_IPC_10
        WORD    DRV_IPC_11
        WORD    DRV_IPC_12
        WORD    DRV_IPC_13
        WORD    DRV_IPC_14
        WORD    DRV_IPC_15

;/*
;** These are the patterns for the base patterns.  Someday clean this up and
;** put it someplace reasonable.  Should have a pointer in the DS to these so
;** they could change based on resoultion.
;*/

        ALIGN  4

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

;/*
;** These are used in the DoOnePlane function.
;*/

        ALIGN   4

MonoConversions LABEL WORD

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

;/*
;** Private functions
;*/

        .CODE

        SUBTITLE DoOnePlane
        PAGE +

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

        ALIGN   4

DoOnePlane PROC SYSCALL PUBLIC

        XOR     EBX,EBX
        SHR     DH,1
        RCL     EBX,1
        SHR     DL,1
        RCL     EBX,1
        ADD     EBX,EBX                         ; Indexing into words
        MOV     BX,MonoConversions[EBX]
        MOV     ECX,SIZE_PATTERN

DoOnePlane_loop:
        MOV     AL,[ESI].DDC.ddc_pa.pa_abMask
        AND     AL,BL
        XOR     AL,BH
        MOV     [EDI],AL
        INC     EDI
        INC     ESI
        LOOP    DoOnePlane_loop
        SUB     ESI,SIZE_PATTERN
        RET

DoOnePlane ENDP

;/*
;** Public functions
;*/

        SUBTITLE rgb_to_ipc
        PAGE +

;/***************************************************************************
;*
;* 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:
;**
;**     VGA:
;**     ----
;**     0:  (00,00,00)
;**     1:  (CC,CC,CC)
;**     2:  (80,00,00)
;**     3:  (FF,00,00)
;**     4:  (80,80,00)
;**     5:  (80,80,80)
;**     6:  (FF,FF,00)
;**     7:  (FF,FF,FF)
;**
;** Given the ordering restriction there are only 13 relevant conditions that
;** separate the color regions.  They are:
;**
;**   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.
;**
;** To determine the region we are in, we'll perform all 13 tests and pack the
;** true/false values into a word.  We'll then examine the WORD for the
;** requirements for each region.
;**
;**
;** The following 8 words show which of the 13 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.
;**
;**             0223464515145
;**
;*/

RGBTrueMap LABEL WORD
        WORD    1000000000000b  ; 0
        WORD    0000000010100b  ; 1
        WORD    0110000000000b  ; 2
        WORD    0001000000000b  ; 3
        WORD    0000101000010b  ; 4
        WORD    0000000101001b  ; 5
        WORD    0000010000000b  ; 6
        WORD    0000000000000b  ; 7

;/*
;** The following 8 words show which of the 13 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 RGBTrueMap, we require the condition to be true.  Otherwise we
;** require it to be false.  If the bit is not on in RGBNeededMap, 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.
;**
;**             0223464515145
;**
;**             2346576176633
;*/

RGBNeededMap LABEL WORD
        WORD    1000000000000b  ; 0
        WORD    0000000110100b  ; 1
        WORD    1110000000000b  ; 2
        WORD    0101000000011b  ; 3
        WORD    0010101000010b  ; 4
        WORD    0000100101001b  ; 5
        WORD    0001011001100b  ; 6
        WORD    0000010010000b  ; 7

;/*
;** 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 LABEL BYTE
        BYTE    DRV_IPC_00,-1,DRV_IPC_00,DRV_IPC_00,\
                 DRV_IPC_00,DRV_IPC_00,-1,DRV_IPC_00
        BYTE    DRV_IPC_08,-1,DRV_IPC_08,DRV_IPC_08,\
                 DRV_IPC_08,DRV_IPC_08,-1,DRV_IPC_08
        BYTE    DRV_IPC_01,-1,DRV_IPC_02,DRV_IPC_02,\
                 DRV_IPC_01,DRV_IPC_04,-1,DRV_IPC_04
        BYTE    DRV_IPC_09,-1,DRV_IPC_10,DRV_IPC_10,\
                 DRV_IPC_09,DRV_IPC_12,-1,DRV_IPC_12
        BYTE    DRV_IPC_03,-1,DRV_IPC_03,DRV_IPC_06,\
                 DRV_IPC_05,DRV_IPC_05,-1,DRV_IPC_06
        BYTE    DRV_IPC_07,-1,DRV_IPC_07,DRV_IPC_07,\
                 DRV_IPC_07,DRV_IPC_07,-1,DRV_IPC_07
        BYTE    DRV_IPC_11,-1,DRV_IPC_11,DRV_IPC_14,\
                 DRV_IPC_13,DRV_IPC_13,-1,DRV_IPC_14
        BYTE    DRV_IPC_15,-1,DRV_IPC_15,DRV_IPC_15,\
                 DRV_IPC_15,DRV_IPC_15,-1,DRV_IPC_15

        ALIGN   4

rgb_to_ipc PROC SYSCALL PUBLIC uses EBX ECX EDI ESI

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

        MOVZX   EAX,AX
        MOVZX   EDX,DX
        XOR     ESI,ESI         ; Clear accumulator
        CMP     AH,DL           ; CF on if c2 < c1
        ADC     ESI,ESI
        CMP     AL,AH           ; CF on if c3 < c2
        ADC     ESI,ESI
        CMP     AL,DL           ; CF on if c3 < c1
        ADC     ESI,ESI         ; ESI = Permutation number
        MOV     EBX,ESI
        ADD     EBX,EBX
        ADD     EBX,offset RGB_Sort
        JMP     EBX

        ALIGN   4

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     EBX,EBX
        XCHG    BL,AH           ; EAX = c3, EBX = c2
        XOR     DH,DH           ; EDX = c1
        XOR     EDI,EDI         ; DI = condition flags
        CMP     DL,40h          ; c1 < 40h
        ADC     EDI,EDI
        CMP     DL,0C0h         ; c1 < C0h
        ADC     EDI,EDI
        CMP     BL,40h          ; c2 < 40h
        ADC     EDI,EDI
        CMP     BL,80h          ; c2 < 80h
        ADC     EDI,EDI
        CMP     AL,40h          ; c3 < 40h
        ADC     EDI,EDI
        CMP     AL,80h
        ADC     EDI,EDI         ; c3 < 80h
        MOV     ECX,EDX
        ADD     ECX,EBX         ; ECX = c1 + c2
        CMP     ECX,180h        ; c1 + c2 < 180h
        ADC     EDI,EDI
        ADD     ECX,EAX         ; ECX = c1 + c2 + c3
        CMP     ECX,1F2h        ; c1 + c2 + c3 < 1F2h
        ADC     EDI,EDI
        CMP     ECX,2AFh        ; c1 + c2 + c3 < 2AFh
        ADC     EDI,EDI
        SUB     ECX,EAX
        SUB     ECX,EAX         ; ECX = c1 + c2
        CMP     ECX,140h        ; c1 + c2 - c3 < 140h
        ADC     EDI,EDI
        SUB     ECX,EAX
        SUB     ECX,EAX
        SUB     ECX,EAX
        ADD     ECX,200h
        CMP     ECX,232h        ; c1 + c2 - 4*c3 < 32h
        ADC     EDI,EDI
        MOV     ECX,EDX
        SUB     ECX,EBX         ; ECX = c1 - c2
        CMP     ECX,80h         ; c1 - c2 < 80h
        ADC     EDI,EDI
        SUB     ECX,EAX
        ADD     ECX,100h        ; ECX = c1 - c2 - c3 + 100h, which is > 0
        CMP     ECX,140h        ; c1 - c2 - c3 < 40h
        ADC     EDI,EDI

;/*
;** 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     EBX,-2

RGB_Region_loop:
        INC     EBX
        INC     EBX
        MOVZX   ECX,RGBTrueMap[EBX]     ; Turn off the TRUE guys
        XOR     ECX,EDI
        AND     CX,RGBNeededMap[EBX]    ; 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     EBX,2
        ADD     EBX,ESI ; EBX = 8 * color + permutation
        MOV     AL,aipcColorAndPerm[EBX]
        XOR     AH,AH

        RET

rgb_to_ipc ENDP

        SUBTITLE synthesize_xparent_mask
        PAGE +

;/***************************************************************************
;*
;* 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         = ESI --> DDC to use                                                          
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4


synthesize_xparent_mask PROC SYSCALL PUBLIC uses EBX EDI ESI

;/*
;** 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,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipcBack
        SHR     AL,1                            ; Isolate the four colors
        SBB     DL,DL                           ; C0 color
                                                ; !!! add some error
        SHR     AL,1                            ; !!! checking here
        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 will then give us our transparency
;** mask.
;*/

        MOV     ECX,SIZE_PATTERN

        mov     edi,esi
        mov     esi,[ESI].DDC.ddc_pa.pa_abColor
ifdef FIREWALLS
        INVOKE  check_brush,
                esi
endif
        push    ebp
SFC_Loop:
        MOV     AL,[ESI][SIZE_PATTERN*0]
        MOV     AH,[ESI][SIZE_PATTERN*1]
        XOR     AX,DX
        XCHG    AX,bp
        MOV     AL,[ESI][SIZE_PATTERN*2]
        MOV     AH,[ESI][SIZE_PATTERN*3]
        XOR     AX,BX
        OR      AX,bp
        OR      AL,AH
        MOV     [EDI].DDC.ddc_pa.pa_abMask,AL
        INC     ESI
        inc     edi
        LOOP    SFC_Loop
        pop     ebp

ifdef FIREWALLS
        INVOKE  check_brush,
                0
endif


        RET

synthesize_xparent_mask ENDP

        SUBTITLE synthesize_color_bits
        PAGE +

;/***************************************************************************
;*
;* 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                                                          
;*                                                                          
;* INPUT         = DS:SI --> DDC to use 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4

synthesize_color_bits PROC SYSCALL PUBLIC uses EDI

        mov     EDI,[ESI].DDC.ddc_pa.pa_abColor ; EDI --> Destination
ifdef FIREWALLS
        INVOKE  check_brush,
                edi
endif
        MOV     DL,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipc
        MOV     DH,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipcBack
        MOV     AL,DL
        AND     AL,DH
        TEST    AL,ONES_OR_ZEROS
        JZ      SCB_Process_bits
        OR      [ESI].DDC.ddc_pa.pa_fb,PA_GRAY

SCB_Process_bits:
        INVOKE  DoOnePlane                      ; Some .ERRNZs in here
        INVOKE  DoOnePlane
        INVOKE  DoOnePlane
        INVOKE  DoOnePlane

ifdef FIREWALLS
        INVOKE  check_brush,
                0
endif
        RET

synthesize_color_bits ENDP


        SUBTITLE synthesize_mono_bits
        PAGE +

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

        ALIGN   4

synthesize_mono_bits PROC SYSCALL PUBLIC

        LEA     EDI,[ESI].DDC.ddc_pa.pa_abMono           ; EDI --> Destination
        MOV     DL,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipc
        MOV     DH,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipcBack
        SHR     DX,4
        .ERRNZ  MONO_BIT - 00010000b
        INVOKE  DoOnePlane
        RET

synthesize_mono_bits ENDP

        SUBTITLE rotate_brush
        PAGE +

;/***************************************************************************
;*
;* 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         = ESI --> DDC to use            
;*                 CL   =  Amount to rotate right
;*
;* OUTPUT        = ESI --> DDC to use  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4

rotate_brush PROC SYSCALL PUBLIC uses EBX EDI

        MOV     EBX,BITS_PEL                    ; Magic number !!!
        mov     EDI,[ESI].DDC.ddc_pa.pa_abColor
ifdef FIREWALLS
        INVOKE  check_brush,
                edi
endif

RB_Loop:
        ROR     BYTE ptr [EDI][0],CL            ; Lets clean this up !!!!
        ROR     BYTE ptr [EDI][1],CL
        ROR     BYTE ptr [EDI][2],CL
        ROR     BYTE ptr [EDI][3],CL
        ROR     BYTE ptr [EDI][4],CL
        ROR     BYTE ptr [EDI][5],CL
        ROR     BYTE ptr [EDI][6],CL
        ROR     BYTE ptr [EDI][7],CL
        ADD     EDI,SIZE_PATTERN
        DEC     EBX
        JNZ     RB_Loop


        MOV     EBX,2                           ; Magic number !!!
        lea     EDI,[ESI].DDC.ddc_pa.pa_abMono

RB_Loop2:
        ROR     BYTE ptr [EDI][0],CL            ; Lets clean this up !!!!
        ROR     BYTE ptr [EDI][1],CL
        ROR     BYTE ptr [EDI][2],CL
        ROR     BYTE ptr [EDI][3],CL
        ROR     BYTE ptr [EDI][4],CL
        ROR     BYTE ptr [EDI][5],CL
        ROR     BYTE ptr [EDI][6],CL
        ROR     BYTE ptr [EDI][7],CL
        ADD     EDI,SIZE_PATTERN
        DEC     EBX
        JNZ     RB_Loop2

ifdef FIREWALLS
        INVOKE  check_brush,
                0
endif
        RET

rotate_brush ENDP

        SUBTITLE copy_bits_to_pattern
        PAGE +

;/***************************************************************************
;*
;* 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) 
;*                 EBX --> DDC                                                     
;*                 ECX   =  Number of bytes per scan of source bitmap              
;*                 EDX   =  Height of bitmap                                       
;*                 ESI --> Destination of bits (first BYTE of pattern bits buffer) 
;*                 EDI --> Source bits (first BYTE of bits buffer)                 
;*                 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4

copy_bits_to_pattern PROC SYSCALL PUBLIC uses EDI ESI

        LOCAL   SrcWidth   :BYTE        ; Width in pels of source
        LOCAL   SrcHeight  :DWORD       ; Height in scans of source
        LOCAL   ScanIncr   :DWORD       ; Increment to next scan of source
        LOCAL   PlaneIncr  :DWORD       ; Incr to next color plane of source
        LOCAL   PlaneCnt   :BYTE        ; Number of color planes in source
        LOCAL   InitScanCnt:BYTE        ; No. scans to copy per plane of src
        LOCAL   ScanCnt    :BYTE        ; Loop counter
        LOCAL   BitFillCnt :BYTE        ; No. empty bits per scan in pattern
        LOCAL   ScanFillCnt:BYTE        ; Number of empty scans in pattern
        LOCAL   BackClr    :BYTE        ; Our version of the background color

        DebugMsg <copy_bits_to_pattern KENZ phycolor.asm>

        PUSH    EBX                     ; save DDC

        cmp     al,0ffh         ;device dependent
        jne     @F
        mov     al,4            ; 4 planes this device
@@:
        cmp     ah,PATTERN_WIDTH
        jg      @F
        mov     ah,PATTERN_WIDTH
@@:

        MOV     PlaneCnt,AL     ; Save number color planes for loop counter
        MOV     SrcWidth,AH     ; Save input to make space for calculations
        MOV     PlaneIncr,ECX   ; Plane increment always bytes-per-scan
        MOV     SrcHeight,EDX   ; 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    EAX,ECX                 ; Get bytes-per-scan into AX,
                                        ; plane cnt in CL
        NEG     EAX                     ; Walking up from lower left, so...
        SHR     CL,1                    ; CL = 2 if color, = 0 if mono
        SHL     EAX,CL                  ; ScanIncr *= 4 if color,
                                        ; unchanged if mono
        .ERRNZ  BITS_PEL - 4
        MOV     ScanIncr,EAX            ; Save the chef d'oeuvre
        NEG     EAX                     ; Want it positive to alter initial
                                        ; EDI
        DEC     EDX                     ; Want bottom scan line
        MUL     EDX                     ; EAX --> Offset bottom scan line
        ADD     EDI,EAX                 ; Save new improved source pointer
        ADD     ESI,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,BYTE ptr [EBX].DDC.ddc_pa.pa_ba.ba_ipcBack
        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     EAX,PATTERN_HEIGHT      ; InitScanCnt = min(8, SrcHeight)
        CMP     EAX,SrcHeight
        JB      @F
        MOV     EAX,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 clr (-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 pstv, we want to add 1
        AND     CL,CH                   ; CL = 0 if was neg, 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     EDX,ScanIncr            ; Src 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    EDI             ; 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,[EDI]        ; Get source BYTE
        AND     AL,AH           ; Clear off unused bits
        OR      AL,BL           ; Fill unused bits with background color
        MOV     [ESI],AL        ; Store BYTE
        DEC     ESI             ; Adjust destination pointer
        ADD     EDI,EDX         ; 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     [ESI],BH        ; Store scan of background color
        DEC     ESI             ; Point to next destination scan
        DEC     AL              ; One less scan to fill
        JNZ     CBP_Fill_extra_scan

CBP_Next_plane:
        POP     EDI             ; Restore pointer to source bits
        ADD     EDI,PlaneIncr   ; Point to next color plane
        ADD     ESI,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     EBX             ; Restore DDC
        MOV     AL,BitFillCnt
        MOV     [EBX].DDC.ddc_pa.pa_cxFill,AL
        MOV     AL,ScanFillCnt
        MOV     [EBX].DDC.ddc_pa.pa_cyFill,AL

        RET

copy_bits_to_pattern ENDP

        SUBTITLE fill_pattern_empty_bits
        PAGE +

;/***************************************************************************
;*
;* 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         = ESI --> DDC 
;* OUTPUT        = direction flag cleared 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        ALIGN   4

fill_pattern_empty_bits PROC SYSCALL PUBLIC

        LOCAL   ScanAdj:DWORD

        CLD                                     ; LODSB/STOSB need this
        MOV     BL,BITS_PEL                     ; Num of planes to loop over
        MOV     BH,BL                           ; Save for 2nd half of subrt
        MOVZX   EDX,[ESI].DDC.ddc_pa.pa_cyFill  ; Get number of scans to fill
        MOV     ScanAdj,EDX                     ; Save for 2nd half of subrt
        OR      EDX,EDX                         ; If no scans to fill
        JZ      FPEB_Chk_cxfill                 ; Check for bits on right side

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

        MOV     AH,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipcBack


        mov     EDI,[ESI].DDC.ddc_pa.pa_abColor
ifdef FIREWALLS
        INVOKE  check_brush,
                edi
endif


@@:
        SHR     AH,1                            ; Put color bit in carry flag
        SBB     AL,AL                           ; AL = 0FFh if color was 1
        MOV     ECX,EDX                         ; Reload scan count
    REP STOSB                                   ; Stuff background color
        ADD     EDI,SIZE_PATTERN                ; Point into next color plane
        SUB     EDI,EDX                         ; Point back to beg of plane
        DEC     BL                              ; Count down number of planes
        JNZ     @B

FPEB_Chk_cxfill:
        MOV     CL,[ESI].DDC.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,[ESI].DDC.ddc_pa.pa_cyFill

FPEB_Es_ok:
        MOV     AH,BYTE ptr [ESI].DDC.ddc_pa.pa_ba.ba_ipcBack
        mov     ESI,[ESI].DDC.ddc_pa.pa_abColor
        ADD     ESI,ScanAdj                     ; ESI = EDI --> first BYTE to
        MOV     EDI,ESI                         ;               update
        MOV     BL,BH                           ; Num 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                              ; Cnt down the scans to alter
        JNZ     @B
        ADD     ESI,ScanAdj                     ; Point to first BYTE in next
                                                ; plane
        MOV     EDI,ESI
        DEC     BL                              ; Count down the color planes
        JNZ     FPEB_Loop_top

FPEB_Exit:
ifdef FIREWALLS
        INVOKE  check_brush,
                0
endif
        RET

fill_pattern_empty_bits ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = alloc_brush 
;*
;* DESCRIPTION   = Allocate storage for a brush
;*
;* INPUT         = EAX = size of block to allocate  
;* OUTPUT        = EAX = pointer to brush
;*
;* RETURN-NORMAL = EAX <> 0
;* RETURN-ERROR  = EAX = 0
;*
;**************************************************************************/
alloc_brush PROC SYSCALL USES EBX
        LOCAL   pBrush:DWORD

        mov     eax,SIZE_PATTERN*BITS_PEL
;ifdef FIREWALLS
        add     eax,SIZE_PATTERN*2
;endif ;FIREWALLS
 
        lea     ebx,pBrush
        INVOKE  private_alloc
        mov     eax,pBrush
        or      ecx,ecx
        jz      alloc_ok
        mov     eax,PMERR_INSUFFICIENT_MEMORY
        save_error_code
        xor eax,eax
alloc_ok:
ifdef FIREWALLS
        push    eax
        add     eax,SIZE_PATTERN*BITS_PEL
        mov     DWORD PTR [eax],BRUSH_VALUE
        mov     DWORD PTR [eax+4],BRUSH_VALUE
        pop     eax
endif ;FIREWALLS
        ret
alloc_brush endp

;/***************************************************************************
;*
;* FUNCTION NAME = free_brush 
;*
;* DESCRIPTION   = Frees allocated storage for a brush
;*
;* INPUT         = EAX - pointer to the storage
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
free_brush PROC SYSCALL
        mov     ecx,eax
        INVOKE  private_free
        ret
free_brush endp

;/***************************************************************************
;*
;* FUNCTION NAME = copy_brush 
;*
;* DESCRIPTION   = copies a brush 
;*
;* INPUT         = DS:SI - brush to copy from
;*                 ES:DI - brush to copy to
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
copy_brush PROC SYSCALL USES ECX ESI EDI
        mov     ecx,SIZE_PATTERN*BITS_PEL
        rep     movsb
        ret
copy_brush endp

ifdef FIREWALLS
.DATA
SaveBrush DWORD ?
.CODE

;/***************************************************************************
;*
;* FUNCTION NAME = check_brush
;*
;* DESCRIPTION   = Checks to see if a brush is valid
;*
;* INPUT         = pBrush: DWORD
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
check_brush PROC SYSCALL USES EAX,
        pBrush:DWORD

        mov     eax,pBrush
        cmp     eax,0
        jz      NoSave
        mov     SaveBrush,eax
NoSave:
        mov     eax,SaveBrush
        add     eax,SIZE_PATTERN*BITS_PEL
        cmp     DWORD PTR [eax],BRUSH_VALUE
        jne     cb_error
        cmp     DWORD PTR [eax+4],BRUSH_VALUE
        je      cb_ok

cb_error:

cb_ok:
        ret
check_brush ENDP
endif ;FIREWALLS

        END
