;*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.;
;*****************************************************************************/
;***********************************************************************
;
;   Module          = CONVERT
;
;   Description     = Routines for converting bitmaps
;
;   Functions       = ConvertExt8ToInt8
;                     ConvertExt8ToInt16
;
;
;***********************************************************************

INCL_PM EQU     1
include os2.inc
include eddinclt.inc
include eddhtype.inc
include eddhmacr.inc

?DF     equ     1       ; we dont want _TEXT segment defined
include cmacros.inc

include rmacros.inc

CONVERTCOMMON   STRUC
cc_BltSpad              DB      SIZE BltSPad DUP (?)
cc_pbExternalBitmap     DD      ?
cc_pExternalHeader      DD      ?
cc_pbhInternalBitmap    DD      ?
cc_pptlScanStart        DD      ?
cc_lScanLines           DD      ?
cc_cInternalBitCount    DW      ?
cc_cExternalBitCount    DW      ?
cc_pbSrcPointer         DD      ?
cc_pbTrgPointer         DD      ?
cc_cx                   DD      ?
cc_pfnRGBToIndex        DD      ?
cc_pfnSetRGBAndInc      DD      ?
cc_usIncrement          DW      ?
cc_usExtTabSize         DW      ?
cc_fbFlags              DB      ?
ifndef  BPP24
cc_ausConvertTable      DW      256 DUP (?)
else
cc_ausConvertTable      DD      256 DUP (?)
endif
cc_pfnvConvertLine      DD      ?
cc_cExternalBytesPerPel DD      ?
cc_ulRLE_last_x         DD      ?
cc_ulRLE_last_y         DD      ?
cc_pbRLE_last_pos       DD      ?
cc_fRLE_delta           DW      ?
cc_fConvertPal          DW      ?
cc_pfnvConvertColour    DD      ?
cc_usColour             DW      ?
cc_ulPelsOnChunkLine    DD      ?
cc_ulLinesInChunk       DD      ?
cc_ulInternalBytesPerLine       DD      ?
cc_ulExternalBytesPerLine       DD      ?
cc_ulExternalCx         DD      ?
cc_ulExternalCy         DD      ?
cc_ulChunkPosX          DD      ?
cc_ulChunkPosY          DD      ?
cc_ulChunkEndX          DD      ?
cc_ulChunkEndY          DD      ?
cc_ulCurrentX           DD      ?
cc_ulCurrentY           DD      ?
cc_ulState              DD      ?
ifdef FIREWALLS
cc_pbExternalEnd        DD      ?
endif
CONVERTCOMMON   ENDS

extrn _SPad :word

;-------------------------------------------------------------------------

_DATA           segment use32 dword public 'DATA'
                assume  cs:FLAT, ds:FLAT, es:FLAT

_DATA           ends


;-------------------------------------------------------------------------

ifdef   BPP24
CONV_TABLE_ENTRY_SIZE    EQU     4
else    ;~BPP24
CONV_TABLE_ENTRY_SIZE    EQU     2
endif


_TEXT           segment use32 dword public 'CODE'
                assume  cs:FLAT, ds:FLAT, es:FLAT

;-------------------------------------------------------------------------
;
; Function:     ConvertExt8ToInt8
;
; Parmeters:    None
;
; Purpose: To convert a scan line from external 8bpp to internal 8bpp
;
; Uses:    The CONVERTCOMMON scratch pad values -
;               cc_pbSrcPointer    - pointer to source pels
;               cc_pbTrgPointer    - pointer to target pels
;               cc_cx              - Number of pels to convert
;               cc_ausConvertTable - The conversion lookup table
;
; After call:
;               cc_pbSrcPointer points to next source pel
;               cc_pbTrgPointer points to next target pel
;               cc_cx unchanged
;
; Assembler version of C code original:
;
; /******************************************************************/
; /* ConvertExt8ToInt8                                              */
; /*                                                                */
; /* Converts a single scan line from external 8bpp to internal 8bpp*/
; /******************************************************************/
; VOID ConvertExt8ToInt8(VOID)
; {
;     ULONG   j;
;
;     /**************************************************************/
;     /* one to one mapping between source and target bits per pixel*/
;     /**************************************************************/
;     for ( j = SPad.cx; j--; )
;     {
;         /**********************************************************/
;         /* put the source byte through the conversion table and   */
;         /* copy to the target                                     */
;         /**********************************************************/
;         *SPad.pbTrgPointer++ =
;                        (BYTE)SPad.ausConvertTable[*SPad.pbSrcPointer++];
;     } /* for each pel on the row */
; } /* ConvertExt8ToInt8 */
;
; Notes:
;       To improve performance 4 bytes are loaded and converted each
;       time around the loop.
;       A second loop is then used to convert any pels remaining after
;       the last DWORD of pels converted by the first loop
;
;-------------------------------------------------------------------------

        align   4
cProc   ConvertExt8ToInt8, <PUBLIC>, <esi, edi, ebx>
cBegin

; use ecx to count down the number of pels
;     esi to point to the source pels (cc_pbSrcPointer)
;     edi to point to the target pels (cc_pbTrgPointer)
;     ebx for storing the source and target pel values

; Set up count, source and target pointers

        mov     ecx, _SPad.cc_cx
        mov     esi, _SPad.cc_pbSrcPointer
        mov     edi, _SPad.cc_pbTrgPointer

; Convert as many pels as possible using the DWORD loop

        xor     ebx, ebx                ; clear ebx

        shr     ecx, 2                  ;divide count by 4
        jz      short convert_singles_8bpp   ;no DWORDs to convert

; Load 4 pels from the source
convert_dword_8bpp:
        lodsd

; Convert the bottom word
        mov     bl, al
        mov     al, BYTE PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        mov     bl, ah
        mov     ah, BYTE PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]

; Get the top word into ax
        swap    eax

; Convert the top word
        mov     bl, al
        mov     al, BYTE PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        mov     bl, ah
        mov     ah, BYTE PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]

; Get the words back in the correct order
        swap    eax

; Store the converted DWORD in the destination
        stosd

; update index and repeat for more DWORDS
        loop    short convert_dword_8bpp

; Load count of remaining pels
convert_singles_8bpp:
        mov     ecx, _SPad.cc_cx
        and     ecx,  00000003h
        jz      short finished_8bpp     ; No extra pels at end

; Loop to convert the bytes remaining after the DWORD loop
; Note they will be the first bytes

single_pel_8bpp:
        lodsb
        mov     bl, al
        mov     al, BYTE PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        stosb
        loop    short single_pel_8bpp

finished_8bpp:

; Store the new values for source and target pointers
        mov     _SPad.cc_pbSrcPointer, esi
        mov     _SPad.cc_pbTrgPointer, edi

cEnd


;-------------------------------------------------------------------------
;
; Function:     ConvertExt8ToInt16
;
; Parmeters:    None
;
; Assembler version of C code original:
;
; /********************************************************************/
; /* ConvertExt8ToInt16                                               */
; /*                                                                  */
; /* Converts a single scan line from external 8bpp to internal 16bpp */
; /********************************************************************/
; VOID ConvertExt8ToInt16(VOID)
; {
;     ULONG   j;
;     RGB16   rgb16Pel;
;
;     /****************************************************************/
;     /* Enter a loop for each external pel.                          */
;     /****************************************************************/
;     for ( j = SPad.cx; j--; )
;     {
;         /************************************************************/
;         /* Don't combine the following two lines together because   */
;         /* the SetInternal16BppPel macro uses the parameter more    */
;         /* than once.                                               */
;         /************************************************************/
;         rgb16Pel = SPad.ausConvertTable[*SPad.pbSrcPointer++];
;         SetInternal16BppPel(rgb16Pel);
;     }
; } /* ConvertExt8ToInt16 */
;-------------------------------------------------------------------------


        align   4
cProc   ConvertExt8ToInt16, <PUBLIC>, <esi, edi, ebx>
cBegin

; use ecx to count down the number of pels
;     esi to point to the source pels (cc_pbSrcPointer)
;     edi to point to the target pels (cc_pbTrgPointer)
;     ebx for storing the source and target pel values

; Set up count, source and target pointers

        mov     ecx, _SPad.cc_cx
        mov     esi, _SPad.cc_pbSrcPointer
        mov     edi, _SPad.cc_pbTrgPointer

; Convert as many pels as possible using the DWORD loop

        xor     ebx, ebx                ; clear ebx

        shr     ecx, 2                  ;divide count by 4
        jz      short convert_singles_16bpp   ;no DWORDs to convert

; Load 4 pels from the source
convert_dword_16bpp:
        lodsd

; store converted word in edx
        mov     edx, eax

; Convert the bottom word
        mov     bl, dh
        mov     ax, WORD PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        xchg    al,ah           ; do an intel byte swap
        shl     eax,16          ; move to top half of dword
        mov     bl, dl
        mov     ax, WORD PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        xchg    al,ah           ; do an intel byte swap

; write out the first 2 converted pels
        stosd

; Convert the top word
        shr     edx,16          ; move top word to lower word

; Convert the top word
        mov     bl, dh
        mov     ax, WORD PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        xchg    al,ah           ; do an intel byte swap
        shl     eax,16          ; move to top half of dword
        mov     bl, dl
        mov     ax, WORD PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        xchg    al,ah           ; do an intel byte swap

; write out the 2nd 2 pels
        stosd

; update index and repeat for more DWORDS
        loop    short convert_dword_16bpp

; Load count of remaining pels
convert_singles_16bpp:
        mov     ecx, _SPad.cc_cx
        and     ecx,  00000003h
        jz      short finished_16bpp    ; No extra pels at end

; Loop to convert the bytes remaining after the DWORD loop
; Note they will be the first bytes

single_pel_16bpp:
        lodsb
        mov     bl, al
        mov     ax, WORD PTR _SPad.cc_ausConvertTable [ebx * CONV_TABLE_ENTRY_SIZE]
        xchg    al,ah           ; do an intel byte swap
        stosw
        loop    short single_pel_16bpp

finished_16bpp:

; Store the new values for source and target pointers
        mov     _SPad.cc_pbSrcPointer, esi
        mov     _SPad.cc_pbTrgPointer, edi
cEnd

;-------------------------------------------------------------------------
;
; Function:     ConvertExt24ToInt8
;
; Parmeters:    None
;
; Assembler version of C code original:
;
;
; /**********************************************************************/
; /* ConvertExt24ToInt8                                                 */
; /*                                                                    */
; /* Converts a single scan line from external 24bpp to internal 8bpp.  */
; /**********************************************************************/
; VOID ConvertExt24ToInt8(VOID)
; {
;     ULONG   j;
;     ULONG   ulTrgIndex;
;     RGB2    RGBColour;
;     RGB2    LastRGBColour;
;
;     /******************************************************************/
;     /* process the first pel separately so we can put an optimization */
;     /* into the loop                                                  */
;     /* this optimization assumes that consecutive pels have the same  */
;     /* colour for a high proportion of the time                       */
;     /******************************************************************/
;     /**********************************************************/
;     /* require three source bytes for each target byte        */
;     /*    - first byte is BLUE                                */
;     /*    - second byte is GREEN                              */
;     /*    - third byte is RED                                 */
;     /**********************************************************/
;     LastRGBColour.bBlue  = *SPad.pbSrcPointer++;
;     LastRGBColour.bGreen = *SPad.pbSrcPointer++;
;     LastRGBColour.bRed   = *SPad.pbSrcPointer++;
;
;     ulTrgIndex = SPad.pfnRGBToIndex(LastRGBColour);
;
;     *SPad.pbTrgPointer++ = (BYTE)ulTrgIndex;
;
;     /**************************************************************/
;     /* process 1 pixel at a time, ie. 1 target byte / 3 source    */
;     /* bytes                                                      */
;     /**************************************************************/
;     for ( j = SPad.cx - 1; j--; )
;     {
;         /**********************************************************/
;         /* require three source bytes for each target byte        */
;         /*    - first byte is BLUE                                */
;         /*    - second byte is GREEN                              */
;         /*    - third byte is RED                                 */
;         /**********************************************************/
;         RGBColour.bBlue  = *SPad.pbSrcPointer++;
;         RGBColour.bGreen = *SPad.pbSrcPointer++;
;         RGBColour.bRed   = *SPad.pbSrcPointer++;
;
;         /**************************************************************/
;         /* if this is the same as the last RGB then we already know   */
;         /* its index                                                  */
;         /**************************************************************/
;         if (LastRGBColour.bBlue  != RGBColour.bBlue  ||
;             LastRGBColour.bGreen != RGBColour.bGreen ||
;             LastRGBColour.bRed   != RGBColour.bRed)
;         {
;             /**********************************************************/
;             /* save the current RGB                                   */
;             /**********************************************************/
;             LastRGBColour = RGBColour;
;
;             /**********************************************************/
;             /* convert the RGB to an index                            */
;             /**********************************************************/
;             ulTrgIndex = SPad.pfnRGBToIndex(RGBColour);
;         }
;
;         *SPad.pbTrgPointer++ = (BYTE)ulTrgIndex;
;     } /* for each pel on the row */
;
; } /* ConvertExt24ToInt8 */
;
;  Note: The last RGB value converted is stored in lastRGB, initially
;        this value has 0xff000000 as it can't match the RGB value
;        read (as the bottom byte is the options and is stripped off)
;-------------------------------------------------------------------------
        align   4
cProc   ConvertExt24ToInt8, <PUBLIC>, <esi, edi, ebx>
                localD   lastRGB
                localD   lastTrgIndex
cBegin

; use ecx to count down the number of pels
;     esi to point to the source pels (cc_pbSrcPointer)
;     edi to point to the target pels (cc_pbTrgPointer)
;     ebx for storing the source and target pel values

; Set up count, source and target pointers

        mov     ecx, _SPad.cc_cx
        mov     esi, _SPad.cc_pbSrcPointer
        mov     edi, _SPad.cc_pbTrgPointer

; Set the last RGB value to an impossible value

        mov     lastRGB, 0ff000000h

; Read the 3 source bytes: BLUE, GREEN, RED into eax : 00RRGGBB
next_RGB2_to_8bpp:
        lodsw
        shl     eax, 16
        lodsb
        swap    eax

; See if this value is the same as the last one
        cmp     eax, lastRGB
        jne     short convert_RGB2_to_8bpp
        mov     eax, lastTrgIndex

; Store the pel in the target bitmap and repeat
        stosb
        loop    short next_RGB2_to_8bpp
        jmp     short finished_RGB2_to_8bpp

; Record the RGB2 value and convert it to the required value
convert_RGB2_to_8bpp:
        mov     lastRGB, eax

        push    ecx
        push    eax
        call    [_SPad.cc_pfnRGBToIndex]
        add     esp, 4
        pop     ecx
        mov     lastTrgIndex, eax

; put the converted pel into the target bitmap and repeat
        stosb
        loop    short next_RGB2_to_8bpp

; Store the new values for source and target pointers
finished_RGB2_to_8bpp:
        mov     _SPad.cc_pbSrcPointer, esi
        mov     _SPad.cc_pbTrgPointer, edi
cEnd

;-------------------------------------------------------------------------
;
; Function:     ConvertExt24ToInt16
;               XGA version (ie not MATROX)
;
; Parmeters:    None
;
; Assembler version of C code original:
;
;
; /**********************************************************************/
; /* ConvertExt24ToInt16                                                */
; /*                                                                    */
; /* Converts a single scan line from external 24bpp to internal 16bpp. */
; /* (No convert table is used at 16 bpp).                              */
; /**********************************************************************/
; VOID ConvertExt24ToInt16(VOID)
; {
;     ULONG   j;
;     RGB16   TrgPel;
;
;     for ( j = SPad.cx; j--; )
;     {
;         TrgPel = RGB16FromPRGB2((PRGB2)SPad.pbSrcPointer);
;         SetInternal16BppPel(TrgPel);
;         SPad.pbSrcPointer += sizeof(RGB);
;     }
; } /* ConvertExt24ToInt16 */
;
; The RGB16FromPRGB2 macros read in 3 bytes from the source in the
; order BLUE, GREEN then RED and converts them to a single 16 bit
; value. This 16 bit value consists of 5 red bits, 6 green bits
; and 5 blue bits in that order. However the 16 bit value is stored
; with the bytes reversed (ie MOTOROLA format) so the format as seen
; by a register is:
;
; ie SOURCE as stored in memory:
;               1st byte BLUE  (B7-B0)
;               2nd byte GREEN (G7-G0)
;               3rd byte RED   (R7-R0)
;
;    TARGET as stored in memory:
;               1st byte R7 R6 R5 R4 R3 G7 G6 G5
;               2nd byte G4 G3 G2 B7 B6 B5 B4 B3
;
;    TARGET as seen in a register:
;               G4 G3 G2 B7 B6 B5 B4 B3 R7 R6 R5 R4 R3 G7 G6 G5
;
;-------------------------------------------------------------------------
        align   4
cProc   ConvertExt24ToInt16, <PUBLIC>, <esi, edi, ebx>
cBegin

; use ecx to count down the number of pels
;     esi to point to the source pels (cc_pbSrcPointer)
;     edi to point to the target pels (cc_pbTrgPointer)
;     ebx for storing the source and target pel values

; Set up count, source and target pointers

        mov     ecx, _SPad.cc_cx
        mov     esi, _SPad.cc_pbSrcPointer
        mov     edi, _SPad.cc_pbTrgPointer

; Read the 3 source bytes: BLUE, GREEN, RED and convert into eax
next_RGB2_to_16bpp:
        lodsw
        shr     ah, 2
        ror     eax, 14
        lodsb
        shr     al, 3
        rol     eax, 11

; Store the pel in the target bitmap and repeat
        ror     ax, 8
        stosw
        loop    short next_RGB2_to_16bpp

; Store the new values for source and target pointers
finished_RGB2_to_16bpp:
        mov     _SPad.cc_pbSrcPointer, esi
        mov     _SPad.cc_pbTrgPointer, edi
cEnd

_TEXT ends

END
