;*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 = dithering program
;*
;*
;* VERSION      V2.0
;*
;* DATE         8/4/92
;*
;* DESCRIPTION  Converted         3 dithering for use in PM
;*              
;* FUNCTIONS    Public: 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                     John Colleran [johnc] Created program
;*   02/15/87                     Walt Moore [waltm] - Initial version
;*****************************************************************************/

.286p
        .xlist
        include cmacros.inc

        include pmgre.inc
        include driver.inc
        include display.inc
        include assert.mac
        .list

sBegin  Data
        externW adrgbDefault
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

sEnd    Data


sBegin  Code
        assumes cs,Code

        externW CodeData
        externD adDitherPatterns

;/*
;******************** New         Compatible RGB Mapping Scheme ****************
;*/

ColorCount  struc
    ccCount     db  ?               ;**   number of colors with ccIndex
    ccIndex     db  ?               ;**   IPC of color
ColorCount  ends

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

Transformation  struc
    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
        dw      128, 128, 0             ;**   origin sub-space 1     x <= 128
        dw      -1,  0,   0             ;**   normal
        dw      128, 128, 0             ;**   origin sub-space 2     x+y <= 256
        dw      -1,  -1,  0             ;**   normal
        dw      128, 128, 128           ;**   origin sub-space 3     x+z <= 256
        dw      -1,  0,   -1            ;**   normal
        dw      255, 255, 0             ;**   origin sub-space 4     all
        dw      -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


;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = 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-ERROR  = None
;*
;**************************************************************************/

cProc   ComputeSymmetry,<NEAR,PUBLIC>
cBegin
        mov     bl,al
        mov     cl,ah
        mov     ch,dl
        xor     ax,ax                   ;** 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
cEnd

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

cProc   MakeDitherBitmap,<NEAR,PUBLIC>,<di>
        parmW   nNumberOfColors

        localW  nOldColorCount
        localW  iLoop
cBegin
        mov     bx,CodeOFFSET abDitherPattern
        xor     ax,ax
        mov     nOldColorCount,ax
MDBMainLoop:
        mov     iLoop,SIZE_PATTERN
        push    di
        push    dx
        push    bx
        mov     ax,nOldColorCount
        add     al,ss:[si].ccCount
        mov     nOldColorCount,ax
        mov     ch,al                   ;**  CH: value to compare with
        inc     si
        .errnz  ccIndex-ccCount-1
        .errnz  ccCount

MDBOuterLoop:
        xchg    dx,bp                   ;**  SS:BP-->pattern bit mask
        mov     ah,[bp]                 ;**  get the previous pattern into AH
        mov     cl,8                    ;**  a byte has 8 bits

MDBInnerPatternLoop_10:                 ;**  compute next bit mask in AL
        cmp     cs:[bx],ch              ;**  if CY make that bit a 1
        rcl     al,1
        inc     bx
        dec     cl
        jnz     MDBInnerPatternLoop_10

        mov     [bp],al                 ;**  save new bitmask
        inc     bp
        xor     al,ah                   ;**  exclude bits from previous mask
        mov     ah,al
        mov     al,ss:[si]              ;**  get color index in AL
        mov     cl,8

MDBInnerPatternLoop_20:
        shl     ah,1
        jnc     MDBInnerPatternLoop_30
        mov     ss:[di],al

MDBInnerPatternLoop_30:
        inc     di
        dec     cl
        jnz     MDBInnerPatternLoop_20

        xchg    dx,bp                   ;** can access local variables again
        dec     iLoop
        jnz     MDBOuterLoop

        inc     si                      ;** SS:SI-->next color index count
        pop     bx
        pop     dx
        pop     di
        dec     nNumberOfColors
        jnz     MDBMainLoop
cEnd

%out    Dither.asm 16 color scheme

;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = ES:DI = written brush
;* RETURN-ERROR  = None
;*
;**************************************************************************/


cProc   WriteBrush,<NEAR,PUBLIC>
cBegin
        push    bp
        mov     bp,SIZE_PATTERN-1
        mov     bx,di
        mov     cx,SIZE_PATTERN         ;** outer loop counter
WPBRowLoop:
        push    cx
        mov     ah,SIZE_PATTERN         ;** inner loop counter
WPBColumnLoop:
        lods    byte ptr ss:[si]
        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     di,bx
        inc     bx
        mov     al,cl
        stosb
        mov     al,ch
        add     di,bp
        stosb
        mov     al,dl
        add     di,bp
        stosb
        mov     al,dh
        add     di,bp
        stosb
        pop     cx
        loop    WPBRowLoop

        pop     bp
cEnd


;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = AX = subspace {0,1,2,3}
;* RETURN-ERROR  = None
;*
;**************************************************************************/

cProc   ComputeSubSpace,<NEAR,PUBLIC>
cBegin
        xor     bh,bh                   ;** zero counter
        mov     si,CodeOFFSET SubDivPlanes
        push    bp

CSSMainLoop:
        xor     di,di                   ;** BL: red, CH: blue, CL: green
        mov     bp,3
CSSMulLoop:
        xor     ax,ax
        mov     al,bl
        sub     ax,word ptr cs:[si]     ;** adjust by origin
        imul    word ptr cs:[si][6]     ;** scale
        inc     si
        inc     si
        xchg    bl,cl                   ;** rotate RGB bytes
        xchg    cl,ch
        add     di,ax
        dec     bp
        jnz     CSSMulLoop

        inc     bh
        add     si,6
        or      di,di                   ;** we are in this subspace iff positive
        js      CSSMainLoop             ;**   (once we go negative we're outside)
        mov     al,bh
        dec     ax
        pop     bp
cEnd


;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = SS:BX = transformed colors
;*                 CS:SI = color Origin xform
;* RETURN-ERROR  = None
;*
;**************************************************************************/
 
cProc   TransformColors,<NEAR,PUBLIC>
cBegin
        assert  ah,E,0
        push    bp
        xor     di,di                   ;**  DI = index.
        mov     cx,3

CTMoveOriginLoop:
        lods    byte ptr cs:[si].xOrigin ;**  adjust by origin
        sub     ss:[bx][di],ax
        inc     di
        inc     di
        loop    CTMoveOriginLoop

        mov     dx,3                    ;**  DX = outer loop counter
CTMainLoop:
        xor     di,di                   ;**  coord index
        xor     bp,bp                   ;**  mult accumulator
        mov     cx,3                    ;**  CX = inner loop counter

CTXformLoop:
        lods    byte ptr cs:[si]        ;**  matrix multiply
        imul    byte ptr ss:[bx][di]
        inc     di
        inc     di
        add     bp,ax
        loop    CTXformLoop

        shr     di,1
        sub     di,dx
        shl     di,1
        mov     ss:[bx][di][6],bp       ;**  store result
        dec     dx
        jnz     CTMainLoop

        add     bx,6
        pop     bp
cEnd


;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = DX = nColors
;* RETURN-ERROR  = None
;*
;**************************************************************************/

cProc   MakeColorCntTable,<NEAR,PUBLIC>
cBegin
        xor     dx,dx
        mov     ax,SIZE_PATTERN*SIZE_PATTERN
        sub     ax,ss:[di][0]
        sub     ax,ss:[di][2]
        sub     ax,ss:[di][4]
        mov     ah,al                   ;** AH = overall brightness factor
        lods    byte ptr cs:[si]
        jz      MCTNoBaseCount
        xchg    al,ah
        mov     ss:[bx],ax
        inc     dx
        inc     bx
        inc     bx
MCTNoBaseCount:
        mov     cx,3

MCTCopyLoop:
        mov     ah,ss:[di]
        inc     di
        inc     di
        lods    byte ptr cs:[si]
        or      ah,ah
        jz      MCTBottomOfLoop
        xchg    al,ah
        mov     ss:[bx],ax
        inc     bx
        inc     bx
        inc     dx
MCTBottomOfLoop:
        loop    MCTCopyLoop
cEnd


;/***************************************************************************
;*
;* 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        = None
;*
;* RETURN-NORMAL = SS:SI = sorted color-count structs
;* RETURN-ERROR  = None
;*
;**************************************************************************/

cProc   SortColorCntTable,<NEAR,PUBLIC>
cBegin
        push    bp
        mov     di,CodeOFFSET PColorIntensities
        mov     ax,cx               ;**  AX = color cound
        shl     ax,1
        sub     sp,ax               ;**  create local space
        mov     bp,sp
        push    ax
        mov     dh,cl               ;**  DH = count

SCTOuterLoop:
        push    cx
        push    si
        xor     bx,bx
        mov     cl,dh
        mov     dl,-1               ;**  Initialize to very bright color

SCTInnerLoop:
        lods    word ptr ss:[si]
        mov     al,ah               ;**  AL = IPC

        CPUMode 386
        movzx   di,al
        mov     al,cs:[di+CodeOFFSET PColorIntensities]
        CPUMode 286                 ;**  AL = brightness of color

        cmp     al,dl               ;**  if this color is dimmer save it
        ja      SCTNextIteration
        mov     dl,al
        mov     bh,bl
SCTNextIteration:
        inc     bx
        loop    SCTInnerLoop

        pop     si
        mov     bl,bh
        xor     bh,bh
        shl     bx,1
        mov     ax,ss:[bx][si]
        mov     [bp],ax
        inc     bx
        inc     bp
        inc     bp
        mov     byte ptr ss:[si][bx],INV_DITHER_IPC ;** mark this color as used
        pop     cx
        loop    SCTOuterLoop

        mov     cl,dh
        pop     dx
        sub     bp,dx
        xchg    si,bp
        mov     di,bp

SCTCopyLoop:
        lods    word ptr ss:[si]
        mov     [bp],ax
        inc     bp
        inc     bp
        loop    SCTCopyLoop

        add     sp,dx
        pop     bp
        mov     si,di
cEnd


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

assumes ds,Data


cProc   dither_brush,<NEAR,PUBLIC>
        localW  nColors                 ;**  distinct colors in dither
        localV  wMappedColors, 12       ;**
        localV  BitMask, 8              ;**
        localV  accStructs, 8           ;**
        localV  TempPatternBitmap, 64   ;**
        localB  nSymmetryIndex          ;**  original symmetry order
cBegin
        push    si

;/*
;**  Clear accelerator flags
;*/
        and     [si].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     cx,cx
        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    cx                      ;**  push grey level

;/*
;**  Now see if this color is one of the standard 16
;*/
        CPUMode 386
        movzx   eax,ax
        xor     ecx,ecx
        mov     cl,dl
        shl     ecx,16                  
        or      eax,ecx                 ;**  EAX is the color the RGB
        mov     es,CodeData
        assumes es,Data
        mov     di,DataOFFSET adrgbDefault
        mov     cx,16
        repne   scasd
        jne     slow_dither

;/*
;**  The color IS one of our favorite 16
;*/
        cmp     di,(DataOFFSET adrgbDefault[BACKGND_DWORD])+4
        je      db_check_color_white
        cmp     di,(DataOFFSET adrgbDefault[FOREGND_DWORD])+4
        jne     db_scan_ok

db_check_color_black:
        cmp     eax,IPCs_API_RGB_00
        je      db_scan_ok
        jmp     short 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      [si].ddc_pa.pa_fb,PA_SINGLE_CLR ;**  They're all solid colors
        sub     di,4+DataOFFSET adrgbDefault
        add     di,CodeOFFSET adDitherPatterns  ;**  DI is the new dither pattern
        mov     ax,cs
        mov     gs,ax
        assumes es,Data

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


        xchg    si,di                   ;**  SI index to pattern, DI is DDC
        ddc?    di
        lea     di,[di].ddc_pa.pa_abColor   ;**  ES:DI color bitmap
        mov     cx,4                    ;**  four planes to write
store_plane_loop:
        lods    byte ptr cs:[si]        ;**  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
        jmp     do_mono_dither
        CPUMode 286

slow_dither:
        lea     di,[si].ddc_pa.pa_abColor
        mov     es,CodeData             ;**  ES:DI color bitmap
        assumes es,nothing

ifdef oldstuff
        xor     eax,eax
        stosd                           ;**  BLUE plane
        stosd
        stosd                           ;**  GREEN plane
        stosd
        stosd                           ;**  RED plane
        stosd
        mov     eax,-1                  ;**  INTENSITY plane
        stosd
        stosd
        jmp     do_mono_dither
endif

@@:
        cCall   ComputeSymmetry         ;** make B >= G >= R, BL, CL, CH
        mov     nSymmetryIndex,al

        push    di                      ;**  save offset to output object
        cCall   ComputeSubSpace         ;** compute which subspace to use
        shl     ax,4
        .errnz  (size Transformation)-16
        mov     si,ax
        add     si,CodeOFFSET 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     bx,wMappedColors
        cCall   TransformColors         ;** on ret. CS:SI-->xCOrigin and
        mov     di,bx                   ;** SS:BX-->transformed colors
        lea     bx,accStructs           ;** SS:BX-->where to put color cnt. struc.
        cCall   MakeColorCntTable
        mov     nColors,dx

;/*
;**  convert the restricted IPC [0-6] to a full IPC [0-15]
;*/
        lea     si,accStructs           ;** SS:SI-->color cnt struc.
        CPUMode 386
        movzx   bx,nSymmetryIndex       ;** BX: symmetry operation to perform
        CPUMode 286
        shl     bx,3                    ;** each lookup table is 8 bytes
        add     bx,CodeOFFSET PColorMap ;** BX = converion table for this ordering
        mov     cx,dx                   ;** CX = count of structs to convert
db_convert:
        lods    word ptr ss:[si]        ;** AX = color-count struct
        mov     al,ah
        xlatb   cs:[bx]                 ;** convert index to full cube IPC
        assert  al,LE,15
        mov     ss:[si][-1],al          ;** store result
        loop    db_convert

        lea     si,accStructs           ;** SS:SI-->color cnt struc.
        mov     cx,nColors
        cmp     cx,1                    ;** no work if only one color
        jbe     db_sorted
        cCall   SortColorCntTable
db_sorted:

        lea     di,TempPatternBitmap    ;** SS:DI-->output obj., SS:SI--> clr.c.
        CPUMode 386
        mov     dword ptr BitMask[0],0  ;** initialize bitmask to zeros
        mov     dword ptr BitMask[4],0
        CPUMode 286
        lea     dx,BitMask              ;** SS:DX-->previous pattern bitmask
        cCall   MakeDitherBitmap,<nColors>   ;** go do the magic.  SS:DI-->tmp bmp
        mov     si,di                   ;** SS:SI-->tmp pattern bitmap (8x8 bytes)
        pop     di                      ;** ES:DI-->output object
        cCall   WriteBrush              ;** convert to EGA/VGA format

do_mono_dither:
        xor     si,si
        pop     dx                      ;** DL = grey level
        cCall   mono_dither             ;** ES:DI = destination
        pop     si                      ;** SI = DDC

        cmp     nColors,1
        jne     exit_dither
        or      [si].ddc_pa.pa_fb,PA_SINGLE_CLR
exit_dither:
cEnd

;/***************************************************************************
;*
;* 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
;*      Calls:
;*            none
;*              
;* INPUT         = DL     =  value to dither
;*                 ES:DI --> destination
;*                 SI     =  previous grey indicator
;* oUTPUT        = None
;*
;* RETURN-NORMAL = 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-ERROR  = None
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   mono_dither,<NEAR,PUBLIC,NODATA>,<ds>
cBegin
        mov     cx,3                    ;** Will be usefull
        xor     bx,bx                   ;** Need a zero a few times
        xchg    ax,si                   ;** Need SI later
        shl     ax,cl                   ;** Update old grey flags
        inc     cx                      ;** 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     si,abMonoBasePatterns[bx]    ;** Copy the base pattern
        cld
        movs    word ptr es:[di],word ptr cs:[si]
        movs    word ptr es:[di],word ptr cs:[si]
        sub     si,cx                   ;** Duplicate for second half of brush
        movs    word ptr es:[di],word ptr cs:[si]
        movs    word ptr es:[di],word ptr cs:[si]
        xchg    ax,si                   ;** 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     bx,cl                   ;** D6:D4 is index into grey_flags
        mov     bl,cs:grey_flags[bx]    ;** Or in grey flag
        or      si,bx

;/*
;**  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      si,si                   ;** Was this one of the greys?
        jz      mono_plane_dithered     ;**   No
        test    si,100b                 ;** If black or white, ignore it
        jnz     mono_dither_exit        ;**   Was black or white
        add     si,si                   ;** Special case the grey
        mov     ax,cs:greys[si][-2]
        sub     di,SIZE_PATTERN
        stosw
        stosw
        stosw
        stosw
        .errnz  SIZE_PATTERN - 8
mono_plane_dithered:
        jmp     short mono_dither_exit

not_base_pattern:
        shr     bx,1                    ;** D5:D2 will index into abRowsMasks
        and     bl,0FEh                 ;** Indexing into words, must be 0
        mov     ax,cs:auRowsMasks[bx]   ;** AL = base row, AH = base mask
        mov     bl,al                   ;** Set base row
        sub     bx,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      es:[di][bx][0],al       ;** Set third bit

second_bit:
        or      es:[di][bx][4],al       ;** Set second bit

first_bit:
        or      es:[di][bx][0],ah       ;** Set first bit

mono_dither_exit:
cEnd

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

        ifdef   LORES
        db      0,80h
        db      2,80h
        db      1,20h
        db      3,20h
        db      0,20h
        db      2,20h
        db      1,80h
        db      3,80h
        db      0,40h
        db      2,40h
        db      1,10h
        db      3,10h
        db      0,10h
        db      2,10h
        db      1,40h
        db      3,40h
        endif

        ifdef   HIRES
        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
        endif


abMonoBasePatterns      label   byte

        ifdef   LORES
        db      000h,000h,000h,000h
        db      088h,000h,000h,000h
        db      088h,000h,088h,000h
        db      088h,022h,088h,000h
        db      088h,022h,088h,022h
        db      0AAh,022h,088h,022h
        db      0AAh,022h,0AAh,022h
        db      0AAh,0AAh,0AAh,022h
        db      0AAh,0AAh,0AAh,0AAh
        db      0EEh,0AAh,0AAh,0AAh
        db      0EEh,0AAh,0EEh,0AAh
        db      0EEh,0BBh,0EEh,0AAh
        db      0EEh,0BBh,0EEh,0BBh
        db      0FFh,0BBh,0EEh,0BBh
        db      0FFh,0BBh,0FFh,0BBh
        db      0FFh,0FFh,0FFh,0BBh
        db      0FFh,0FFh,0FFh,0FFh
        endif

        ifdef   HIRES
        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

sEnd    Code
endif ;** VGA
end
