;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = COLORMAT.ASM
;*
;* DESCRIPTIVE NAME = Color matching routines. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/15/88
;*
;* DESCRIPTION  
;*
;* FUNCTIONS    Public rgb_to_ipc_with_pal    
;*                     rgb_to_ipc_with_hwpal
;*                     rgb_to_ipc_with_pal_6  
;*                     MatchTwoPalettes       
;*                     MapDownPaletteIndex    
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/15/88                     Created By: GunterZ [Gunter Zieber]
;  Wed 06-Sep-1989 13:40:33 -by- Bob Grudem [bobgru]
; Ported to PM (removed most of it).
;*****************************************************************************/

        .286p
        .xlist

        include cmacros.inc
INCL_DDIMISC            equ                      1
INCL_GRE_BITMAPS        equ                      1
INCL_GPIBITMAPS         equ                      1
INCL_GPILOGCOLORTABLE   equ                      1
INCL_DEV                equ                      1
INCL_DDICOMFLAGS        equ                      1
        include pmgre.inc
DINCL_BITMAP            equ                      1
        include driver.inc
        include display.inc
        include njmp.mac
        include assert.mac
        include palette.inc
        .list

        ??_out  colormat

sBegin  PalSeg
        assumes cs,PalSeg

;/***************************************************************************
;*
;* FUNCTION NAME = MapDownPaletteIndex
;*
;* DESCRIPTION   = 
;*
;*     Maps the given index (iIndex) into the first iMaxIndex+1 entries of
;*     the palette pPal.  iIndex is a valid index into pPal, but the
;*     situation requires an index that can be no larger than iMaxIndex.
;*
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Registers Preserved:
;*                       SI,DI,BP,DS
;*                 Calls: 
;*                       rgb_to_ipc_with_pal
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   MapDownPaletteIndex,<FAR,PUBLIC,NODATA>,<bx,si,di,ds>
        parmW   iIndex
        parmD   pPal
        parmW   iMaxIndex

        localW  usOldMax
        localD  rgb
cBegin
        lds     si,pPal
        assumes ds,nothing

;/*
;** Temporarily fake out the driver to think that the palette contains
;** iMaxIndex+1 entries.
;*/

        mov     ax,[si].palseg_usMax
        mov     usOldMax,ax
        mov     ax,iMaxIndex
        mov     [si].palseg_usMax,ax

;/*
;** Get the RGB corresponding to iIndex in pPal.
;*/
        mov     bx,iIndex
        palOff  bx
        mov     ax,word ptr [si+bx].palseg_apalclr.palclr_rgb.rgb2_bBlue
        mov     rgb.lo,ax
        mov     ax,word ptr [si+bx].palseg_apalclr.palclr_rgb.rgb2_bRed
        mov     rgb.hi,ax
        cCall   rgb_to_ipc_with_pal,<rgb,pPal>

;/*
;** Restore the correct number of palette entries.
;*/
        mov     bx,usOldMax
        mov     [si].palseg_usMax,bx
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = MatchTwoPalettes
;*
;* DESCRIPTION   = Build a translation table to go from one palette to another. 
;*                 Unused entries in the source table are filled with 0.
;*
;*                 Flags for fsCmd:
;*                       MTP_6_BITS      equ                      00000001b
;*                       MTP_HWPAL       equ                      00000010b
;*                       MTP_LIMIT_SIZE  equ                      00000100b
;*                
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Registers Preserved:
;*                       SI,DI,BP,DS
;*                 Calls: 
;*                       rgb_to_ipc_with_pal
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   MatchTwoPalettes,<FAR,PUBLIC,NODATA>,<si,di,ds>
        parmD   pPal1
        parmD   pPal2
        parmD   pXlatTbl
        parmW   fsCmd
cBegin

;/*
;** initialize loop parameters
;**
;** DS:SI --> first source rgb
;** CX = number of rgb's
;*/

        lds     si,pPal1
        assumes ds,nothing

        palSize cx,ds,si
        test    fsCmd,MTP_LIMIT_SIZE
        jz      mtp_size_ok
        cmp     cx,SIZE_HW_PAL
        jbe     mtp_size_ok
        mov     cx,SIZE_HW_PAL
mtp_size_ok:
        add     si,palseg_apalclr.palclr_rgb

;/*
;** initialize the translation table
;*/
        push    cx
        cld
        les     di,pXlatTbl
        assumes es,nothing
        xor     ax,ax
        shr     cx,1
        rep     stosw
        rcl     cx,1
        rep     stosb
        mov     di,pXlatTbl.lo
        pop     cx

;/*
;** Fill in the xlat table, one entry for each source palette color.
;*/

mtp_next_source_rgb_bytes:
        lodsw
        xchg    ax,dx
        lodsw
        farPtr  myRGB,ax,dx
        cCall   rgb_to_ipc_with_pal,<myRGB,pPal2>
        stosb
        add     si,(SIZE PALCLR) - (SIZE RGB2)
        loop    mtp_next_source_rgb_bytes

mtp_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = rgb_to_ipc_with_pal
;*
;* DESCRIPTION   = Given a logical palette and the RGB that is to be matched  
;*                 to that palette, this routine returns the index of first   
;*                 closest match that was found.  Color matching is performed 
;*                 by minimizing the geometric distance (in RGB euclidian     
;*                 space) between the RGB to be matched and the RGB values in 
;*                 the palette.  The color matching weights are R=G=B=1.      
;*                 (isotropic)                                                
;*
;*                 This routine considers all 8 bits of each color component   
;*                 when computing the closest match, and searches the palette  
;*                 linearly.                                                   
;*
;*                 Registers Preserved:
;*                       BX,CX,SI,DI,BP,DS,ES
;*
;* INPUT         = NONE
;* OUTPUT        = AL = index of closest match                   
;*                 AH = mono bit status of AL
;*                 DX = error term for match (0 ==> exact match)
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   far_rgb_to_ipc_with_pal,<FAR,PUBLIC,NODATA>,<>
        parmD   rgbIn
        parmD   pPal
cBegin
        cCall   rgb_to_ipc_with_pal,<rgbIn,pPal>
cEnd

cProc   rgb_to_ipc_with_pal,<NEAR,PUBLIC,NODATA>,<bx,cx,dx,si,di,ds>
        parmD   rgbIn
        parmD   pPal

        localW  lMinLo
        localB  lMinHi
        localW  wIndex
        localW  nNumEntries
        localW  wStart
cBegin
        xor     ax,ax
        mov     wStart,ax
        dec     ax
        mov     lMinLo,ax                         ; initialize error term to some
        mov     lMinHi,al                         ; hideously large value (00ffffffh)
        mov     bx,rgbIn.lo                       ; blue->BL, green->BH
        mov     dx,rgbIn.hi                       ; red->DL
        lds     si,pPal                           ; now get the logical color table
        assumes ds,nothing
        palSize cx,ds,si,SIZE_HW_PAL
        mov     nNumEntries,cx
        add     si,palseg_apalclr.palclr_rgb ; move pointer to index/color table

rti8_loop:
        sub     dh,dh
        mov     al,[si].rgb2_bRed                ; get logical red
        sub     al,dl                             ; subtract red we want
        jnc     rti8_square_red                  ; if the result was negative change
        neg     al                                ; the sign of the difference
rti8_square_red:
        mul     al                                ; square difference now
        mov     di,ax                             ; and save it in di

        mov     al,[si].rgb2_bGreen              ; now do the same thing with green
        sub     al,bh
        jnc     rti8_square_green                ; if the result was negative change
        neg     al                                ; the sign of the difference
rti8_square_green:
        mul     al
        add     di,ax
        adc     dh,dh

        mov     al,[si].rgb2_bBlue               ; now compute delta B squared
        sub     al,bl
        jnc     rti8_square_blue                 ; if the result was negative change
        neg     al                                ; the sign of the difference
rti8_square_blue:
        mul     al
        add     di,ax
        adc     dh,0

        or      di,di                             ; look for exact match
        jnz     rti8_not_exact

        or      dh,dh
        jnz     rti8_not_exact
        mov     wIndex,cx
        jmp     short rti8_exit                  ; done with search.

rti8_not_exact:
        cmp     lMinHi,dh                         ; colors.  Compare current error term
        jb      rti8_loop_bottom                 ; with minimal error found previously
        ja      rti8_new_lmin                     ; and swap them if necessary
        cmp     lMinLo,di
        jbe     rti8_loop_bottom

rti8_new_lmin:
        mov     wIndex,cx
        mov     lMinHi,dh
        mov     lMinLo,di

rti8_loop_bottom:
        add     si,SIZE PALCLR                    ; update pointer to next entry
        loop    rti8_loop

rti8_exit:
        mov     ax,nNumEntries
        sub     ax,wIndex
        add     ax,wStart

        mov     bx,rgbIn.lo
        mov     dx,rgbIn.hi

;/*
;** Make AH = IPC status flags
;*/
        CPUMode 386
        add     bl,bh
        setc    bh
        add     bl,dl
        adc     bh,0
        cmp     bx,180h
        jb      rti8_mono_bit_done
        or      ah,HIGH MONO_BIT
        cmp     al,0
        je      rti8_set_ones_or_zeros
        cmp     al,0FFh
        jne     rti8_mono_bit_done
rti8_set_ones_or_zeros:
        or      ah,HIGH ONES_OR_ZEROS
        .errnz  LOW MONO_BIT
        .errnz  HIGH MONO_BIT - 00000001b
        CPUMode 286
rti8_mono_bit_done:
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = rgb_to_ipc_with_hwpal
;*
;* DESCRIPTION   = Given a palette (the device's physical palette) and the RGB  
;*                 that is to be matched to that palette, this routine returns  
;*                 the index of first closest match that was found.  Color      
;*                 matching is performed by minimizing the geometric distance   
;*                 (in RGB euclidian space) between the RGB to be matched and   
;*                 the RGB values in the palette.  The color matching weights   
;*                 are R=G=B=1.  (isotropic)                                    
;*
;*                 This routine considers the high 6 bits of each color         
;*                 component when computing the closest match, and searches the 
;*                 palette in three passes:  the lower 8 reserved colors, the   
;*                 upper 8 reserved colors, the middle 240 colors.              
;*
;*                 Registers Destroyed:
;*                       BX,CX,DS
;*                 Registers Preserved:
;*                       SI,DI,BP,ES
;*                 Calls: 
;*                       inner_rgb_to_ipc_with_hwpal
;*
;* INPUT         = NONE
;* OUTPUT        = AX = closest match                  
;*                 DX = error term (0 ==> exact match) 
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   far_rgb_to_ipc_with_hwpal,<FAR,PUBLIC,NODATA>,<>
        parmD   rgbIn
        parmD   pPal
cBegin
        cCall   rgb_to_ipc_with_hwpal,<rgbIn,pPal>
cEnd

cProc   rgb_to_ipc_with_hwpal,<NEAR,PUBLIC,NODATA>,<cx,si,di,ds>
        parmD   rgbIn
        parmD   pPal

        localW  lMinLo
        localB  lMinHi
        localW  wIndex
        localW  cSubArray
        localW  wAdj
        localW  crgb
        localW  crgbReserved
cBegin
        test    rgbIn.rgb2_fcOptions,PC_RESERVED
        jz      rtihw_not_reserved

        xor     ax,ax                             ; match to black for now
        mov     dx,07FFFh                         ; really     error
        jmp     rtihw_exit                        ; we are matched and done

rtihw_not_reserved:
        xor     ax,ax
        mov     wAdj,ax
        dec     ax
        mov     lMinLo,ax                         ; initialize error term to some
        mov     lMinHi,al                         ; hideously large value (00ffffffh)
        mov     bx,rgbIn.lo                       ; blue->bl, green->bh
        mov     dx,rgbIn.hi                       ; red->dl
        mov     ax,0FCFCh                         ; mask to clear out unused bits
        and     bx,ax                             ; clear out the unused bits
        and     dl,al                             ; 

        lds     si,pPal                           ; DS:SI --> physical palette
        assumes ds,nothing
        mov     crgb,SIZE_HW_PAL
        mov     cx,NUM_RESERVED_CLRS
        mov     crgbReserved,cx

;/*
;** try first half of reserved colors
;*/
        shr     cx,1                              ; cx is our loop counter
        mov     cSubArray,cx
        save    <si>
        cCall   inner_rgb_to_ipc_with_hwpal
        jc      rtihw_got_it

;/*
;** try second half of reserved colors
;*/
        push    si
        mov     cx,crgb
        sub     cx,cSubArray
        mov     wAdj,cx
        rgbOff  cx
        add     si,cx
        mov     cx,cSubArray
        cCall   inner_rgb_to_ipc_with_hwpal
        pop     si
        jc      rtihw_got_it

;/*
;** try non-reserved colors
;*/
        mov     cx,cSubArray
        mov     wAdj,cx
        rgbOff  cx
        add     si,cx
        mov     cx,crgb
        sub     cx,crgbReserved
        mov     cSubArray,cx
        cCall   inner_rgb_to_ipc_with_hwpal

rtihw_got_it:
        mov     ax,wIndex

        mov     dx,lMinLo
        mov     cl,lMinHi
        shr     cl,1
        rcr     dx,1
        shr     cl,1
        rcr     dx,1
rtihw_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = inner_rgb_to_ipc_with_hwpal
;*
;* DESCRIPTION   = Returns the closest match to a color in a specified subset of
;*                 a palette.  Matching is done based on the upper 6 bits of    
;*                 each color component.  The given color is not matched with   
;*                 palette colors marked as PC_RESERVED.                        
;*
;*                 Registers Preserved:
;*                       BX,CX,SI,DI,BP,DS,ES
;*
;* INPUT         = SS:BP --> stack frame for rgb_to_ipc_with_hwpal
;*                 BL = blue  and 0FCh
;*                 BH = green and 0FCh
;*                 DL = red   and 0FCh
;*                 CX = loop limit
;*                 DS:SI --> palseg_apalclr
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes ds,nothing
        assumes es,nothing

cProc   inner_rgb_to_ipc_with_hwpal,<NEAR,PUBLIC,NODATA>,<>
cBegin  <nogen>

irtih_loop:
        test    [si].rgb2_fcOptions,PC_RESERVED
        jnz     irtih_loop_bottom                ; do not match to reserved entry

        sub     dh,dh
        mov     al,[si].rgb2_bRed     ; get logical red
        and     al,0FCh                           ; clear out unused bits
        sub     al,dl                             ; subtract red we want
        jnc     irtih_square_red                 ; if the result was negative change
        neg     al                                ; the sign of the difference
irtih_square_red:
        mul     al                                ; square difference now
        mov     di,ax                             ; and save it in di

        mov     al,[si].rgb2_bGreen   ; now do the same thing with green
        and     al,0FCh                           ; clear out unused bits
        sub     al,bh
        jnc     irtih_square_green
        neg     al
irtih_square_green:
        mul     al
        add     di,ax
        adc     dh,dh

        mov     al,[si].rgb2_bBlue    ; now compute delta B squared
        and     al,0FCh                           ; clear out unused bits
        sub     al,bl
        jnc     irtih_square_blue
        neg     al
irtih_square_blue:
        mul     al
        add     di,ax
        adc     dh,0

        or      di,di                             ; look for exact match
        jnz     irtih_not_exact
        or      dh,dh
        jnz     irtih_not_exact
        mov     lMinLo,di                         ; perfect match found
        mov     lMinHi,dh
        mov     ax,cSubArray
        sub     ax,cx                             ; get subarray index of match
        add     ax,wAdj                           ; adjust for start of subarray
        mov     wIndex,ax
        stc
        jmp     short irtih_exit                 ; done with search.

irtih_not_exact:
        cmp     lMinHi,dh                         ; colors.  Compare current error term
        jb      irtih_loop_bottom                ; with minimal error found previously
        ja      irtih_new_lmin                    ; and swap them if necessary
        cmp     lMinLo,di
        jbe     irtih_loop_bottom

irtih_new_lmin:
        mov     ax,cSubArray
        sub     ax,cx                             ; get subarray index
        add     ax,wAdj                           ; adjust for start of subarray
        mov     wIndex,ax
        mov     lMinHi,dh
        mov     lMinLo,di

irtih_loop_bottom:
        add     si,(SIZE RGB2)                         ; update pointer to next entry
        loop    irtih_loop
        clc

irtih_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = rgb_to_ipc_with_pal_6                                                  
;*                                                                                        
;* DESCRIPTION   = Given a logical palette and the RGB that is to be matched to           
;*                 that palette, this routine returns the index of first closest          
;*                 match that was found.  Color matching is performed by                  
;*                 minimizing the geometric distance (in RGB euclidian space)             
;*                 between the RGB to be matched and the RGB values in the                
;*                 palette.  The color matching weights are R=G=B=1.                      
;*                 (isotropic)                                                            
;*                                                                                        
;*                 This routine considers the high 6 bits of each color                    
;*                 component when computing the closest match, and searches the            
;*                 palette linearly.                                                       
;*                                                                                         
;*                 Registers Destroyed:
;*                       BX,CX,DS
;*                 Registers Preserved:
;*                       SI,DI,BP,ES
;*
;* INPUT         = NONE
;* OUTPUT        = AX = closest match                  
;*                 DX = error term (0 ==> exact match) 
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   far_rgb_to_ipc_with_pal_6,<FAR,PUBLIC,NODATA>,<>
        parmD   rgbIn
        parmD   pPal
cBegin
        cCall   rgb_to_ipc_with_pal_6,<rgbIn,pPal>
cEnd

cProc   rgb_to_ipc_with_pal_6,<NEAR,PUBLIC,NODATA>,<cx,si,di,ds>
        parmD   rgbIn
        parmD   pPal

        localW  lMinLo
        localB  lMinHi
        localW  wIndex
        localW  cSubArray
        localW  wAdj
cBegin
        xor     ax,ax
        mov     wAdj,ax
        dec     ax
        mov     lMinLo,ax                         ; initialize error term to some
        mov     lMinHi,al                         ; hideously large value (00ffffffh)
        mov     bx,rgbIn.lo                       ; blue->bl, green->bh
        mov     dx,rgbIn.hi                       ; red->dl
        mov     ax,0FCFCh                         ; mask to clear out unused bits
        and     bx,ax                             ; clear out the unused bits
        and     dl,al                             ; 

        lds     si,pPal                           ; DS:SI --> physical palette
        assumes ds,nothing

        palSize cx,ds,si,SIZE_HW_PAL
        mov     cSubArray,cx
        add     si,palseg_apalclr.palclr_rgb

rti6_loop:
        sub     dh,dh
        mov     al,[si].rgb2_bRed     ; get logical red
        and     al,0FCh                           ; clear out unused bits
        sub     al,dl                             ; subtract red we want
        jnc     rti6_square_red                  ; if the result was negative change
        neg     al                                ; the sign of the difference
rti6_square_red:
        mul     al                                ; square difference now
        mov     di,ax                             ; and save it in di

        mov     al,[si].rgb2_bGreen   ; now do the same thing with green
        and     al,0FCh                           ; clear out unused bits
        sub     al,bh
        jnc     rti6_square_green
        neg     al
rti6_square_green:
        mul     al
        add     di,ax
        adc     dh,dh

        mov     al,[si].rgb2_bBlue    ; now compute delta B squared
        and     al,0FCh                           ; clear out unused bits
        sub     al,bl
        jnc     rti6_square_blue
        neg     al
rti6_square_blue:
        mul     al
        add     di,ax
        adc     dh,0

        or      di,di                             ; look for exact match
        jnz     rti6_not_exact
        or      dh,dh
        jnz     rti6_not_exact
        mov     lMinLo,di                         ; perfect match found
        mov     lMinHi,dh
        mov     ax,cSubArray
        sub     ax,cx                             ; get subarray index of match
        add     ax,wAdj                           ; adjust for start of subarray
        mov     wIndex,ax
        stc
        jmp     short rti6_exit                  ; done with search.

rti6_not_exact:
        cmp     lMinHi,dh                         ; colors.  Compare current error term
        jb      rti6_loop_bottom                 ; with minimal error found previously
        ja      rti6_new_lmin                     ; and swap them if necessary
        cmp     lMinLo,di
        jbe     rti6_loop_bottom

rti6_new_lmin:
        mov     ax,cSubArray
        sub     ax,cx                             ; get subarray index
        add     ax,wAdj                           ; adjust for start of subarray
        mov     wIndex,ax
        mov     lMinHi,dh
        mov     lMinLo,di

rti6_loop_bottom:
        add     si,(SIZE PALCLR)                 ; update pointer to next entry
        loop    rti6_loop
        clc

rti6_exit:
        mov     ax,wIndex

        mov     dx,lMinLo
        mov     cl,lMinHi
        shr     cl,1
        rcr     dx,1
        shr     cl,1
        rcr     dx,1
cEnd
sEnd    PalSeg
end
