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

ifdef CLR256
else  ;CLR256
;/*****************************************************************************
;*
;* SOURCE FILE NAME = DITHER.ASM
;*
;* DESCRIPTIVE NAME = Dither brush related functions.
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/11/90
;*
;* DESCRIPTION  This module contains dither brush related functions for 16
;*              color dithering scheme used on the EGA/VGA (and 8514 when the
;*              palette is restricted.)
;*
;*
;* FUNCTIONS    ComputeSymmetry
;*              MakeDitherBitmap
;*              WriteBrush
;*              ComputeSubSpace
;*              TransformColors
;*              MakeColorCntTable
;*              SortColorCntTable
;*              dither_brush
;*              mono_dither
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/11/90                     Written by John Colleran [johnc]
;*
;*****************************************************************************/

        .386

        .xlist

DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include pmgre.inc
        include driver.inc
        include assert.mac
        include extern.inc
        include protos.inc

        .list

        .MODEL FLAT

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

        .DATA


IPCs_API_RGB_00 equ     00000000h       ; black                  00h
IPCs_API_RGB_15 equ     00FFFFFFh       ; white                 03Fh
BACKGND_DWORD   equ     0*4             
FOREGND_DWORD   equ     7*4             

ColorCount      struct

    ccCount     db  ?               ; number of colors with ccIndex
    ccIndex     db  ?               ; IPC of color

ColorCount      ends

PlaneEquation   struct

    peOrigin    dw  3 dup(0)        ; An origin and normal to that origin
    peNormal    dw  3 dup(0)        ; define a plane

PlaneEquation  ends

Transformation  struct

    xOrigin     db  3 dup(0)        ; defines a tranform which will transform
    xMatrix     db  9 dup(0)        ; an RGB into a specially weighted RGB
    xCOrigin    db  0               ; which all components add up to 64 (?)
    xBase       db  3 dup(0)

Transformation  ends

;/*
;** PColorIntensities is a ordering of the EGA/VGA palette entries from
;** dark to light
;*/

INV_DITHER_IPC  equ  8

PColorIntensities   label   byte    ;IPC

        db      0                   ;0  black
        db      01h                 ;1  dark blue
        db      03h                 ;2  dark green
        db      05h                 ;3  dark turquoise  (BG)
        db      02h                 ;4  dark red
        db      04h                 ;5  purple          (RB)
        db      06h                 ;6  mustard
        db      07h                 ;7  gray
        db      0ffh                ;8  light gray      ;Not used in dither
        db      09h                 ;9  blue
        db      0bh                 ;10 green
        db      0dh                 ;11 turquoise (cyan)(BG)
        db      0ah                 ;12 red
        db      0ch                 ;13 pink (magenta)  (RB)
        db      0eh                 ;14 yellow
        db      0fh                 ;15 white

;/*
;** abDitherPattern is a an array of bits dispersed so that if pixels
;** are placed in the brush bitmap in the order specified below they
;** will tend to minimize checker-boarding
;*/

abDitherPattern  label   byte

    db   0, 32,  8, 40,  2, 34, 10, 42
    db  48, 16, 56, 24, 50, 18, 58, 26
    db  12, 44,  4, 36, 14, 46,  6, 38
    db  60, 28, 52, 20, 62, 30, 54, 22
    db   3, 35, 11, 43,  1, 33,  9, 41
    db  51, 19, 59, 27, 49, 17, 57, 25
    db  15, 47,  7, 39, 13, 45,  5, 37
    db  63, 31, 55, 23, 61, 29, 53, 21

;/*
;** maps limited color tetrahedron vertices to full color cube
;*/

PColorMap       label   byte

        db 0, 1, 3, 7, 09h, 0Bh, 0Fh, 0FFh
        db 0, 2, 3, 7, 0Ah, 0Bh, 0Fh, 0FFh
        db 0, 1, 5, 7, 09h, 0Dh, 0Fh, 0FFh
        db 0, 4, 5, 7, 0Ch, 0Dh, 0Fh, 0FFh
        db 0, 4, 6, 7, 0Ch, 0Eh, 0Fh, 0FFh
        db 0, 2, 6, 7, 0Ah, 0Eh, 0Fh, 0FFh
        db 0, 4, 5, 7, 0Ch, 0Dh, 0Fh, 0FFh

;/*
;** Plane definitions used to divide the limited color tetrahedron
;*/

SubDivPlanes    label   word

        DWORD   128, 128, 0             ; origin sub-space 1     x <= 128
        DWORD   -1,  0,   0             ; normal
        DWORD   128, 128, 0             ; origin sub-space 2     x+y <= 256
        DWORD   -1,  -1,  0             ; normal
        DWORD   128, 128, 128           ; origin sub-space 3     x+z <= 256
        DWORD   -1,  0,   -1            ; normal
        DWORD   255, 255, 0             ; origin sub-space 4     all
        DWORD   -1,  0,   0             ; normal

;/*
;** Transforms applied to an RGB to map it into the given tetrahedron space
;*/

TransformTable  label   word

        db      32, 32, 0               ; origin
        db      -2, 0,  0               ; 3x3 matrix
        db      2,  -2, 0
        db      0,  0,  2
        db      2,  0,  1, 3            ;pts 3, 1, 2, 4 - IPC of vertices

        db      32, 32, 0               ; origin
        db      -2, -2, 0               ; 3x3 matrix
        db      2,  0,  0
        db      0,  0,  2
        db      2,  1,  4, 3            ;pts 3, 2, 5, 4 - IPC of vertices

        db      32, 32, 0               ; origin
        db      1,  -1, 0               ; 3x3 matrix
        db      1,  1,  0
        db      0,  0,  2
        db      2,  4,  5, 3            ;pts 3, 5, 6, 4 - IPC of vertices

        db      64, 0,  0               ; origin
        db      -2, 0,  0               ; 3x3 matrix
        db      0,  1,  -1
        db      1,  0,  1
        db      4,  3,  5, 6            ;pts 5, 4, 6, 7 - IPC of vertices


        .CODE
_TUNE segment USE32 PUBLIC 'CODE'
;/***************************************************************************
;*
;* FUNCTION NAME = ComputeSymmetry
;*
;* DESCRIPTION   = Given an RGB determine the symmetrical ordering
;*                 This maps any RGB into 1/6 of the color cube.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX
;*
;* INPUT         = DX:AX  =  RGB color (AL=blue, AH=green, DL=red)
;* OUTPUT        = BL: red < CL: < green < CH: blue
;*                 AX = Ordering (symmetry index)
;*
;*                 AX   Original Order
;*                 -------------------
;*                 000  BL < CL < CH
;*                 001  CL < BL < CH
;*                 010  BL < CH < CL
;*                 011  xxxxxxxxxxxx
;*                 100  CH < CL < BL
;*                 101  CL < CH < BL
;*                 110  CH < BL < CL
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ComputeSymmetry PROC  SYSCALL  PUBLIC

        mov     bl,al
        mov     cl,ah
        mov     ch,dl
        xor     eax,eax                 ;zero counter

        cmp     bl,ch                   ;is BL greater or equal CH?
        ja      CheckPlane2             ;if so, don't transpose (ja==jc)
        xchg    bl,ch                   ;transpose

CheckPlane2:

        rcl     ax,1                    ;put carry flag into LSB of AX
        cmp     cl,ch                   ;is CL greater or equal CH?
        ja      CheckPlane3
        xchg    cl,ch

CheckPlane3:

        rcl     ax,1
        cmp     bl,cl                   ;is BL greater or equal CL?
        ja      ComputeSymmetryDone
        xchg    bl,cl

ComputeSymmetryDone:

        rcl     ax,1

                RET

ComputeSymmetry ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = MakeDitherBitmap
;*
;* DESCRIPTION   = Creates a pattern with the specified colors
;*
;*                 Registers Preserved:
;*                       DI,BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,SI
;*
;* INPUT         = SS:SI = color-count structures
;*                 SS:DI = destination
;*                 SS:DX = pattern bitmap mask
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

MakeDitherBitmap        PROC SYSCALL USES edi,   nNumberOfColors:DWORD
                        LOCAL   nOldColorCount:DWORD,
                                iLoop:DWORD


        lea     ebx,abDitherPattern
        xor     eax,eax
        mov     nOldColorCount,eax

MDBMainLoop:

        mov     iLoop,SIZE_PATTERN
        push    edi
        push    edx
        push    ebx
        mov     eax,nOldColorCount

        ASSUME  esi:PTR ColorCount

        add     al,[esi].ccCount
        mov     nOldColorCount,eax
        mov     ch,al                   ;CH: value to compare with
        inc     esi

        .errnz  ColorCount.ccIndex-ColorCount.ccCount-1

        .errnz  ColorCount.ccCount

MDBOuterLoop:

        xchg    edx,ebp                 ;SS:BP-->pattern bit mask
        mov     ah,BYTE PTR [ebp]       ;get the previous pattern into AH
        mov     cl,8                    ;a byte has 8 bits

MDBInnerPatternLoop_10:                 ;compute next bit mask in AL

        cmp     [ebx],ch                ;if CY make that bit a 1
        rcl     al,1
        inc     ebx
        dec     cl
        jnz     MDBInnerPatternLoop_10

        mov     BYTE PTR [ebp],al       ;save new bitmask
        inc     ebp
        xor     al,ah                   ;exclude bits from previous mask
        mov     ah,al
        mov     al,BYTE PTR [esi]       ;get color index in AL
        mov     cl,8

MDBInnerPatternLoop_20:

        shl     ah,1
        jnc     MDBInnerPatternLoop_30


        mov     BYTE PTR [edi],al

MDBInnerPatternLoop_30:

        inc     edi
        dec     cl
        jnz     MDBInnerPatternLoop_20

        xchg    edx,ebp                 ;can access local variables again
        dec     iLoop
        jnz     MDBOuterLoop

        inc     esi                     ;SS:SI-->next color index count
        pop     ebx
        pop     edx
        pop     edi
        dec     nNumberOfColors
        jnz     MDBMainLoop

                        RET

MakeDitherBitmap        ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = WriteBrush
;*
;* DESCRIPTION   = Write the bits to the DDC brush; basically a bit to planar
;*                 conversion
;*
;*                 Registers Preserved:
;*                      DS,ES,BP
;*                 Registers Destroyed:
;*                      AX,BX,CX,DX,DI,SI
;*
;* INPUT         = ES:DI = -> abColor Brush in DDC
;*                 SS:SI = -> array of IPCs (the new pattern)
;* OUTPUT        = ES:DI = written brush
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

WriteBrush      PROC SYSCALL

        push    ebp
        mov     ebp,SIZE_PATTERN-1
        mov     ebx,edi
        mov     ecx,SIZE_PATTERN        ;outer loop counter

WPBRowLoop:

        push    ecx
        mov     ah,SIZE_PATTERN         ;inner loop counter

WPBColumnLoop:

        lods    BYTE PTR [esi]
        shr     al,1
        rcl     cl,1
        shr     al,1
        rcl     ch,1
        shr     al,1
        rcl     dl,1
        shr     al,1
        rcl     dh,1
        dec     ah
        jnz     WPBColumnLoop

        mov     edi,ebx
        inc     ebx
        mov     al,cl
        stosb
        mov     al,ch
        add     edi,ebp
        stosb
        mov     al,dl
        add     edi,ebp
        stosb
        mov     al,dh
        add     edi,ebp
        stosb
        pop     ecx
        loop    WPBRowLoop

        pop     ebp

                RET

WriteBrush      ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = ComputeSubSpace
;*
;* DESCRIPTION   = Determines SubSpace in the limited color space of the
;*                 specified colors
;*
;*                 Registers Preserved:
;*                       BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI
;*
;* INPUT         = BL > CH > CL = (well ordered) RGB
;* OUTPUT        = AX = subspace {0,1,2,3}
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ComputeSubSpace PROC SYSCALL

        movzx   ebx,bl                  ; zero counter
        lea     esi,SubDivPlanes
        push    ebp

CSSMainLoop:

        xor     edi,edi                 ;BL: red, CH: blue, CL: green
        mov     ebp,3

CSSMulLoop:

        xor     eax,eax
        mov     al,bl
        sub     eax,DWORD PTR [esi]     ;adjust by origin
        imul    DWORD PTR [esi][12]     ;scale
        add     esi,4                   ;     FIX SL% 12-19-91
        xchg    bl,cl                   ;rotate RGB bytes
        xchg    cl,ch
        add     edi,eax
        dec     ebp
        jnz     CSSMulLoop

        inc     bh
        add     esi,12                  
        or      edi,edi                 ;we are in this subspace if positive
        js      CSSMainLoop             ;  (once we go negative we're outside)
        mov     al,bh
        dec     eax
        pop     ebp

                RET

ComputeSubSpace ENDP
;/***************************************************************************
;*
;* FUNCTION NAME = TransformColors
;*
;* DESCRIPTION   = Transforms the specified colors SS:BX by transform CS:SI
;*
;*                 Registers Preserved:
;*                       BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,DI,SI
;*
;* INPUT         = SS:BX = mapped RGB
;*                 CS:SI = transform
;* OUTPUT        = SS:BX = transformed colors
;*                 CS:SI = color Origin xform
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

TransformColors PROC SYSCALL

        assert  ah,E,0

        push    ebp
        xor     edi,edi                 ; DI = index.
        mov     ecx,3

CTMoveOriginLoop:

        ASSUME  esi:PTR Transformation

        lodsb   [esi].xOrigin           ; adjust by origin
        sub     [ebx][edi],ax
        inc     edi
        inc     edi
        loop    CTMoveOriginLoop

        mov     edx,3                   ; DX = outer loop counter

CTMainLoop:

        xor     edi,edi                 ; coord index
        xor     ebp,ebp                 ; mult accumulator
        mov     ecx,3                   ; CX = inner loop counter

CTXformLoop:

        lodsb                           ; matrix multiply
        imul    byte ptr [ebx][edi]
        inc     edi
        inc     edi
        add     ebp,eax
        loop    CTXformLoop

        shr     edi,1
        sub     edi,edx
        shl     edi,1
        mov     [ebx][edi][6],ebp       ; store result
        dec     edx
        jnz     CTMainLoop

        add     ebx,6
        pop     ebp

                RET

TransformColors ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = MakeColorCntTable
;*
;* DESCRIPTION   = Determines the number of colors for this dither
;*
;*                 Registers Preserved:
;*                       BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI
;*
;* INPUT         = SS:DI = transformed color
;*                 SS:BX = dest color-count structs
;*                 CS:SI = transform (.xCOrigin)
;*
;* OUTPUT        = DX = nColors
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

MakeColorCntTable       PROC SYSCALL

        xor     edx,edx
        mov     eax,SIZE_PATTERN*SIZE_PATTERN
        sub     ax,[edi][0]
        sub     ax,[edi][2]
        sub     ax,[edi][4]
        mov     ah,al                   ;AH = overall brightness factor
        lodsb
        jz      MCTNoBaseCount
        xchg    al,ah
        mov     WORD PTR [ebx],ax
        inc     edx
        inc     ebx
        inc     ebx

MCTNoBaseCount:

        mov     ecx,3

MCTCopyLoop:

        mov     ah,BYTE PTR [edi]
        inc     edi
        inc     edi
        lodsb
        or      ah,ah
        jz      MCTBottomOfLoop
        xchg    al,ah
        mov     WORD PTR [ebx],ax
        inc     ebx
        inc     ebx
        inc     edx

MCTBottomOfLoop:

        loop    MCTCopyLoop

                        RET

MakeColorCntTable       ENDP


;/***************************************************************************
;*
;* FUNCTION NAME = SortColorCntTable
;*
;* DESCRIPTION   = Sorts the colors for this dither based on brightnest
;*                 (dim to bright)
;*
;*                 Registers Preserved:
;*                       BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,DI,SI
;*
;* INPUT         = CX = count of color-count structs
;*                 SS:SI = array of color-count structs
;*
;* OUTPUT        = SS:SI = sorted color-count structs
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

SortColorCntTable       PROC SYSCALL

        DebugMsg <SortColorCntTable DITHER CLIFFL>

        push    ebp
        lea     edi,PColorIntensities
        mov     eax,ecx             ; AX = color cound
        shl     eax,1
        sub     esp,eax             ; create local space
        mov     ebp,esp
        push    eax
        mov     dh,cl               ; DH = count

SCTOuterLoop:

        push    ecx
        push    esi
        xor     ebx,ebx
        mov     cl,dh
        mov     dl,-1               ; Initialize to very bright color

SCTInnerLoop:

        lodsw
        mov     al,ah               ; AL = IPC

        movzx   edi,al
        mov     al,BYTE PTR [edi+OFFSET PColorIntensities]
                                    ; AL = brightness of color

        cmp     al,dl               ; if this color is dimmer save it
        ja      SCTNextIteration
        mov     dl,al
        mov     bh,bl

SCTNextIteration:

        inc     ebx
        loop    SCTInnerLoop

        pop     esi
        mov     bl,bh
        movzx   ebx,bl
        shl     ebx,1
        mov     ax,WORD PTR [ebx][esi]
        mov     WORD PTR [ebp],ax
        inc     ebx
        inc     ebp
        inc     ebp
        mov     byte ptr [esi][ebx],INV_DITHER_IPC ;mark this color as used
        pop     ecx
        loop    SCTOuterLoop

        mov     cl,dh
        pop     edx
        sub     ebp,edx
        xchg    esi,ebp
        mov     edi,ebp

SCTCopyLoop:

        lodsw
        mov     WORD PTR [ebp],ax
        inc     ebp
        inc     ebp
        loop    SCTCopyLoop

        add     esp,edx
        pop     ebp
        mov     esi,edi

                        RET

SortColorCntTable       ENDP

;/*
;** We want to force these greys to be a solid gray, so we have a special
;** test for them
;*/
SPECIAL_GRAY            equ     0CCh      ; VGA 0xCCCCCC

;/***************************************************************************
;*
;* FUNCTION NAME = dither_brush
;*
;* DESCRIPTION   = Dithers the RGB in DX:AX into the DDC's abColor and
;*                 abMono bitmaps The 8514 uses this routine for the
;*                 restricted palette case (as dither_brush16)
;*
;*                 Registers Preserved:
;*                       SI,BP,DS
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,DI,ES,GS
;*
;* INPUT         = DS:SI --> ddc
;*                 DX:AX = RGB (AL=B, AH=G, DL=R)
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

dither_brush    PROC SYSCALL
                LOCAL   nColors:DWORD,
                        wMappedColors[12]:WORD,
                        BitMask[8]:DWORD,
                        accStructs[8]:DWORD,
                        TempPatternBitmap[64]:DWORD,
                        nSymmetryIndex:BYTE

        push    esi

;/*
;** Clear accelerator flags
;*/

        ASSUME  esi:PTR DDC

        and     [esi].ddc_pa.pa_fb,not (PA_SINGLE_CLR or PA_GRAY)

;/*
;** Compute a gray scale for mono_dither and save it on the stack
;*/

        xor     ecx,ecx
        mov     cl,dl
        add     cl,al
        rcr     cl,1                    ; DL = (R+B)/2
        add     cl,ah
        rcr     cl,1                    ; DL = G/2+(R+B)/4
        push    ecx                     ; push grey level

;/*
;** Now see if this color is one of the standard 16
;*/

        movzx   eax,ax
        xor     ecx,ecx
        mov     cl,dl
        shl     ecx,16                  
        or      eax,ecx                 ; EAX is the color the RGB
        lea     edi,adrgbDefault
        mov     ecx,16
        repne   scasd
        jne     slow_dither

;/*
;** The color IS one of our favorite 16
;*/

        cmp     edi,(OFFSET adrgbDefault[BACKGND_DWORD])+4
        je      db_check_color_white
        cmp     edi,(OFFSET adrgbDefault[FOREGND_DWORD])+4
        jne     db_scan_ok

db_check_color_black:
        cmp     eax,IPCs_API_RGB_00
        je      db_scan_ok
        jmp     db_get_next


db_check_color_white:
        cmp     eax,IPCs_API_RGB_15
        je      db_scan_ok

db_get_next:
        repne   scasd
        jne     slow_dither


db_scan_ok:
        or      [esi].ddc_pa.pa_fb,PA_SINGLE_CLR   ; They're all solid colors
        sub     edi,4+OFFSET adrgbDefault
        add     edi,OFFSET adDitherPatterns        ; DI is the new dither pattern

;/*
;** Store the pattern into abColor
;** For the 8514 its done pixel wise otherwise its planar
;*/

        xchg    esi,edi                 ; SI index to pattern; DI is DDC

        ddc?    edi
        ASSUME  edi:PTR DDC
        push    edi
        mov     edi,[edi].ddc_pa.pa_abColor   ; ES:DI color bitmap
        mov     ecx,4                   ; four planes to write

store_plane_loop:

        lodsb                           ; AL bits for this plane
        mov     ah,al                   ; lets move the bits word at a time
        stosw
        stosw
        stosw
        stosw

        .errnz  (SIZE_PATTERN - 8)

        loop    store_plane_loop
;endif
        pop     edi
        lea     edi,[edi].ddc_pa.pa_abMono
        jmp     do_mono_dither


slow_dither:

        push    esi                     ; DAK save DDC
        mov     edi,[esi].ddc_pa.pa_abColor

@@:
        INVOKE  ComputeSymmetry         ;make B >= G >= R; BL, CL, CH

        mov     nSymmetryIndex,al

        push    edi                      ;save offset to output object

        INVOKE   ComputeSubSpace         ;compute which subspace to use

        shl     eax,4

        .errnz  (size Transformation)-16

        mov     esi,eax
        add     esi,OFFSET TransformTable ;CS:SI tranform for this subspace

                                        ;map [0-255] -> [0-63] for each color
        assert  ah,E,0

        mov     al,bl                   ;Blue
        shr     al,1
        adc     al,ah
        shr     al,1                    ;AL = blue divided by 4
        mov     word ptr wMappedColors[0],ax
        mov     al,cl                   ;Green
        shr     al,1
        adc     al,ah
        shr     al,1
        mov     word ptr wMappedColors[2],ax
        mov     al,ch                   ;Red
        shr     al,1
        adc     al,ah
        shr     al,1
        mov     word ptr wMappedColors[4],ax

        lea     ebx,wMappedColors

        INVOKE  TransformColors         ;on ret. CS:SI-->xCOrigin and
        mov     edi,ebx                 ;  SS:BX-->transformed colors
        lea     ebx,accStructs          ;SS:BX-->where to put color cnt. struc.

        INVOKE  MakeColorCntTable

        mov     nColors,edx

;/*
;** convert the restricted IPC [0-6] to a full IPC [0-15]
;*/

        lea     esi,accStructs          ;SS:SI-->color cnt struc.
        movzx   ebx,nSymmetryIndex      ;BX: symmetry operation to perform
        shl     ebx,3                   ;each lookup table is 8 bytes
        add     ebx,OFFSET PColorMap    ;BX = converion table for this ordering
        mov     ecx,edx                 ;CX = count of structs to convert

db_convert:

        lodsw                           ;AX = color-count struct
        mov     al,ah
        xlatb   [ebx]                   ;convert index to full cube IPC

        assert  al,LE,15

        mov     BYTE PTR [esi][-1],al           ;store result
        loop    db_convert

        lea     esi,accStructs          ;SS:SI-->color cnt struc.
        mov     ecx,nColors
        cmp     ecx,1                   ;no work if only one color
        jbe     db_sorted

        INVOKE  SortColorCntTable

db_sorted:

        lea     edi,TempPatternBitmap   ;SS:DI-->output obj., SS:SI--> clr.c.
        mov     BitMask[0],0            ;initialize bitmask to zeros
        mov     BitMask[4],0
        lea     edx,BitMask             ;SS:DX-->previous pattern bitmask

        INVOKE  MakeDitherBitmap,nColors   ;go do the magic.    SS:DI-->tmp bmp

        mov     esi,edi                 ;SS:SI-->tmp pattern bitmap (8x8 bytes)
        pop     edi                     ;ES:DI-->output object

        INVOKE  WriteBrush              ;convert to EGA/VGA format

        pop     edi                     ; DAK get DDC back
        ASSUME  edi:PTR DDC             ; DAK
        lea     edi,[edi].ddc_pa.pa_abMono

do_mono_dither:

        xor     esi,esi
        pop     edx                     ;DL = grey level

        INVOKE  mono_dither             ;ES:DI = destination

        pop     esi                     ;SI = DDC

        cmp     nColors,1
        jne     exit_dither
        or      [esi].ddc_pa.pa_fb,PA_SINGLE_CLR

exit_dither:

                RET

dither_brush    ENDP
;/***************************************************************************
;*
;* FUNCTION NAME = mono_dither
;*
;* DESCRIPTION   =
;*
;*        This function takes value between 0 - 255 and uses it to create
;*        an 8x8 pile of bits that can be used as a brush.  It does this
;*        by reducing the input value to a number between 0 - 64 and then
;*        turns on that many bits in the 8x8 field.  Thus the value 0 leads
;*        to brush of all zeros, a 255 value leads to a brush of all 1's,
;*        and a value of 128 leads to grey.
;*
;*        The algorithm is equivalent to turning on bits based on an array:
;*
;*             0 32  8 40  2 34 10 42
;*            48 16 56 24 50 18 58 26
;*            12 44  4 36 14 46  6 38         This table favors devices like
;*            60 28 52 20 62 30 54 22         the Hercules card where the
;*             3 35 11 43  1 33  9 41         aspect ratio is close to 1:1
;*            51 19 59 27 49 17 57 25
;*            15 47  7 39 13 45  5 37
;*            63 31 55 23 61 29 53 21
;*
;*             0 32 16 48  2 34 18 50
;*            24 56  8 40 26 58 10 42         This table favors devices like
;*             4 36 20 52  6 38 22 54         the CGA card where the aspect
;*            28 60 12 44 30 62 14 46         ratio is close to 2:1
;*             3 35 19 51  1 33 17 49
;*            27 59 11 43 25 57  9 41
;*             7 39 23 55  5 37 21 53
;*            31 63 15 47 29 61 13 45
;*
;*
;*        Where given a value between 0 - 64, turn on the bit if the array
;*        value is less then the desired value.
;*
;*        When dithering for color drivers, where each plane is dither
;*        independantly, this algorithm has a nice side effect in that
;*        for any value n < m, n is a proper subset of m (any bit turned
;*        on in n must have been turned on in m!).
;*
;*        For the 1:1 table, undesirable patterns are generated for light
;*        and dark grey.  These will be flagged when encountered.  For the
;*        2:1 table,  vertical lines are generated for grey, so they will
;*        be flagged when encountered.  The brush realization routines
;*        can then substitute the correct grey (we cannot do it because
;*        we do not know if the other planes of a color brush were the
;*        same pattern).
;*
;*        Reference:  A Survey of Techniques for the Display of Continuous
;*                    Tone Pictures on Bilevel Displays,;
;*                    Jarvis, Judice, & Ninke;
;*                    COMPUTER GRAPHICS AND IMAGE PROCESSING 5, pp 13-40, (1976)
;*
;*         Registers Destroyed:
;*               AX,BX,CX,DX,FLAGS
;*         Registers Preserved:
;*               none
;*
;* INPUT         = DL     =  value to dither
;*                 ES:DI --> destination
;*                 SI     =  previous grey indicator
;*
;* OUTPUT        = ES:DI --> next destination (ES:DI + SIZE_PATTERN)
;*                 DH     =  dither value (0-64)
;*                 SI     =  New grey indicator (SI << 3 || grey_indicator)
;*                             D2:D0 = 001b for dark  grey
;*                             D2:D0 = 010b for grey
;*                             D2:D0 = 011b for light grey
;*                             D2:D0 = 100b for black
;*                             D2:D0 = 101b for white
;*                             D2:D0 = 000b otherwise
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

mono_dither     PROC SYSCALL

        mov     ecx,3                   ;Will be usefull
        xor     ebx,ebx                 ;Need a zero a few times
        xchg    eax,esi                 ;Need SI later
        shl     eax,cl                  ;Update old grey flags
        inc     ecx                     ;4 will be useful later

        shr     dl,1                    ;Convert value 0-255 into
        adc     dl,bl                   ;  value 0 - 64
        shr     dl,1
        mov     bl,dl                   ;base_pattern index is D6:D2
        mov     dh,dl                   ;Return mapped value to caller in DL
        and     bl,11111100b

        lea     esi,abMonoBasePatterns[ebx]    ;Copy the base pattern
        cld
        movsw
        movsw
        sub     esi,ecx                 ;Duplicate for second half of brush
        movsw
        movsw
        xchg    eax,esi                 ;Restore grey flags

        test    dl,00000011b            ;A base pattern?
        jnz     not_base_pattern
        test    dl,00001111b            ;A grey to special case?
        jnz     mono_dither_exit        ;  No, it is not
        shr     ebx,cl                  ;D6:D4 is index into grey_flags
        mov     bl,grey_flags[ebx]      ;Or in grey flag
        or      esi,ebx

;/*
;** The mono_dither algorithm may generate an undesirable gray
;** (for 404040 and C0C0C0), so these are
;** special cased to a known grey that will be uniform across the
;** devices, and is known to have a satisfactory appearance.
;*/

        or      esi,esi                 ;Was this one of the greys?
        jz      mono_plane_dithered     ;  No
        test    esi,100b                ;If black or white, ignore it
        jnz     mono_dither_exit        ;  Was black or white
        add     esi,esi                 ;Special case the grey
        mov     ax,greys[esi][-2]
        sub     edi,SIZE_PATTERN
        stosw
        stosw
        stosw
        stosw

        .errnz  SIZE_PATTERN - 8

mono_plane_dithered:

        jmp     mono_dither_exit


not_base_pattern:

        shr     ebx,1                   ;D5:D2 will index into abRowsMasks
        and     bl,0FEh                 ;Indexing into words, must be 0
        mov     ax,auRowsMasks[ebx]     ;AL = base row, AH = base mask
        mov     bl,al                   ;Set base row
        sub     ebx,8                   ;Adjust for di pointing past brush
        mov     al,ah                   ;Shift pattern for proper use
        shr     al,cl                   ;AH is base pattern, AL is base >> 4

        and     dl,11b                  ;Dispatch as needed
        cmp     dl,2                    ;CL = 2
        jb      first_bit
        je      second_bit

third_bit:

        or      BYTE PTR [edi][ebx][0],al       ;Set third bit

second_bit:

        or      BYTE PTR [edi][ebx][4],al       ;Set second bit

first_bit:

        or      BYTE PTR [edi][ebx][0],ah       ;Set first bit

mono_dither_exit:

                RET

mono_dither     ENDP

_TUNE ENDS
        .DATA

page

;/*
;**       The grey_flags table contains the values to OR into the
;**       accumulated grey flag for colors which mapped to the
;**       greys which must be special cased.
;*/


greys       label   word

            db      088h,022h       ;Dark grey dither
            db      0AAh,055h       ;Grey dither
            db      0DDh,077h       ;Light grey dither

grey_flags  label   byte

            db      100b            ;Black      (00)
            db      001b            ;Dark Grey  (16)
            db      010b            ;Grey       (32)
            db      011b            ;Light Grey (48)
            db      101b            ;White      (64)

;/*
;**       The order in which the rows of the dither are accessed
;**       are as follows:
;**
;**           0,4,0,4,2,6,2,6             ;For low resolution
;**           1,5,1,5,3,7,3,7
;**           0,4,0,4,2,6,2,6
;**           1,5,1,5,3,7,3,7
;**           0,4,0,4,2,6,2,6
;**           1,5,1,5,3,7,3,7
;**           0,4,0,4,2,6,2,6
;**           1,5,1,5,3,7,3,7
;**
;**           0,4,0,4,2,6,2,6             ;For high resolution
;**           0,4,0,4,2,6,2,6
;**           1,5,1,5,3,7,3,7
;**           1,5,1,5,3,7,3,7
;**           0,4,0,4,2,6,2,6
;**           0,4,0,4,2,6,2,6
;**           1,5,1,5,3,7,3,7
;**           1,5,1,5,3,7,3,7
;**
;**
;**       The order in which bits are turned on is as follows:
;**
;**           80,08,08,80,80,08,08,80     ;For low resolutions
;**           20,02,02,20,20,02,02,20
;**           20,02,02,20,20,02,02,20
;**           80,08,08,80,80,08,08,80
;**           40,04,04,40,40,04,04,40
;**           10,01,01,10,10,01,01,10
;**           10,01,01,10,10,01,01,10
;**           40,04,04,40,40,04,04,40
;**
;**           80,08,08,80,20,02,02,20     ;For high resolution
;**           20,02,02,20,80,08,08,80
;**           40,04,04,40,10,01,01,10
;**           10,01,01,10,40,04,04,40
;**           40,04,04,40,10,01,01,10
;**           10,01,01,10,40,04,04,40
;**           80,08,08,80,20,02,02,20
;**           20,02,02,20,80,08,08,80
;**
;**
;**       If you work in groups of four, the following observations
;**       can be made about how the pixels are visited:
;**
;**       The rows are always accessed as follows:
;**
;**               row n
;**               row n+4
;**               row n
;**               row n+4
;**
;**
;**       The bits are always manipulated as follows:
;**
;**               bit n
;**               bit n >> 4
;**               bit n >> 4
;**               bit n
;**
;**
;**       Since base patterns are defined at intervals of four, the
;**       algorithm for turning on the remaining 1, 2, or 3 bits
;**       can be table driven.
;**
;**
;**       The following table will contain the row and the bitmask to
;**       use for turning on the remaining 1, 2, or 3 bits of the pattern.
;**       Bits D5:D2 of the mapped color are used to index into this table.
;**       The format is:
;**
;**               db      base row, base bit
;*/

auRowsMasks label   word
        db      0,80h
        db      2,20h
        db      0,20h
        db      2,80h
        db      1,40h
        db      3,10h
        db      1,10h
        db      3,40h
        db      0,40h
        db      2,10h
        db      0,10h
        db      2,40h
        db      1,80h
        db      3,20h
        db      1,20h
        db      3,80h



abMonoBasePatterns      label   byte
        db      000h,000h,000h,000h
        db      088h,000h,000h,000h
        db      088h,000h,022h,000h
        db      0AAh,000h,022h,000h
        db      0AAh,000h,0AAh,000h
        db      0AAh,044h,0AAh,000h
        db      0AAh,044h,0AAh,011h
        db      0AAh,055h,0AAh,011h
        db      0AAh,055h,0AAh,055h
        db      0EEh,055h,0AAh,055h
        db      0EEh,055h,0BBh,055h
        db      0FFh,055h,0BBh,055h
        db      0FFh,055h,0FFh,055h
        db      0FFh,0DDh,0FFh,055h
        db      0FFh,0DDh,0FFh,077h
        db      0FFh,0FFh,0FFh,077h
        db      0FFh,0FFh,0FFh,0FFh

endif ;CLR256

;_TUNE ENDS
end
