;*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 = STRCHBLT.ASM
;*
;* DESCRIPTIVE NAME = StretchBlt at level of device driver.
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/03/90
;*
;* DESCRIPTION  StretchBlt at level of device driver.
;*
;*
;* FUNCTIONS    OEMStretchBlt
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   07/03/90                     Written by Viroon Touranachun
;*
;*****************************************************************************/


        .386

        .xlist

        OPTION  OLDSTRUCTS

INCL_GPIBITMAPS         equ     1       ; for bitmap info structure
INCL_DDIMISC            equ     1       ; for BBP structure
INCL_DDICOMFLAGS        equ     1
INCL_DOSERRORS          equ     1
INCL_FONTFILEFORMAT     equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_SCANS          equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIERRORS          equ     1
INCL_GPIPRIMITIVES      equ     1
INCL_GRE_DCS            equ     1
INCL_SAADEFS            equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include pmgre.inc
        include driver.inc
        include display.inc
        include egafam.inc
        include oemblt.inc
        include assert.mac
        include extern.inc
        include protos.inc

        .list

        .MODEL FLAT

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

        .DATA

        EXTERN  asDDARun        :DWORD         ; CMPLCODE.ASM
        EXTERN  asPlaneBuff     :BYTE         ; CMPLCODE.ASM

OSB_Y_SHRINK            equ     01h     ; compression in vertical direction
OSB_HUGE_BITMAP         equ     02h     ; huge source bitmap
XOS_NEXT_MONO_PLANE     equ     2       ; the mono=>color munge entry size

        temp_buf           db 1024 dup (0)

        .CODE


;/***************************************************************************
;*
;* FUNCTION NAME = OEMStretchBlt
;*
;* DESCRIPTION   = This function is a working routine to do the stretchblt
;*                 from a memory bitmap directly (ROP_SRCCOPY) to the
;*                 screen.
;*
;*
;*
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/



OEMStretchBlt   PROC SYSCALL USES edi esi, pddcDst :DWORD,
                                        xDst    :DWORD,
                                        yDst    :DWORD,
                                        psdSrc  :DWORD,
                                        spacer  :DWORD,
                                        lpParm  :DWORD,
                                        cxExt   :DWORD,
                                        cyExt   :DWORD
                LOCAL   xSrcOrg         :DWORD
                LOCAL   ySrcOrg         :DWORD
                LOCAL   cxSrcExt        :DWORD
                LOCAL   cySrcExt        :DWORD
                LOCAL   xDstOrg         :DWORD
                LOCAL   yDstOrg         :DWORD
                LOCAL   cxDstExt        :DWORD
                LOCAL   cyDstExt        :DWORD
                LOCAL   cyErrorTerm     :DWORD
                LOCAL   lpBits          :DWORD
                LOCAL   selFirstSeg     :DWORD
                LOCAL   npSrcLastScan   :DWORD
                LOCAL   lpScreen        :DWORD
                LOCAL   pfnXDDAScan     :DWORD
                LOCAL   pfnCopyScan     :DWORD
                LOCAL   cbSrcPlane      :DWORD
                LOCAL   cbSrcScan       :DWORD
                LOCAL   cbDstScan       :DWORD
                LOCAL   cxSrcVisPel     :DWORD
                LOCAL   cbDstMidByte    :DWORD
                LOCAL   XSI             :DWORD
                LOCAL   XDI             :DWORD
                LOCAL   XDX             :DWORD
                LOCAL   bkmix           :BYTE       ;DCR37
                LOCAL   bkclr           :BYTE       ;DCR37
                LOCAL   cxDstFirstShft  :BYTE
                LOCAL   cxDstLastShft   :BYTE
                LOCAL   bDstFirstMask   :BYTE
                LOCAL   bDstLastMask    :BYTE
                LOCAL   fbStBlt         :BYTE
                LOCAL   bForeClr        :BYTE
                LOCAL   bBackClr        :BYTE

                LOCAL   scan_per_bank   :WORD
                LOCAL   dst_scan_line_left:WORD
                LOCAL   d_page          :BYTE
        DebugMsg <OEMStrectchBlt STRCHBLT CLIFFL>
        cld
        xor     eax,eax
        mov     fbStBlt,al              ; initialize the flag


;----------------------------------------------------------------------
;Check for background mixes of BM_SRCTRANSPARENT or BM_DESTTRANSPARENT.
;BM_SRCTRANSPARENT will result in pels from the source bitmap matching
; the presentation space background color NOT to be copied to the
; destination bitmap. (OVERLAY)
;BM_DESTTRANSPARENT will result in pels from the source bitmap ONLY
; being copied to the destination pels that match the presentation space
; background color. (UNDERLAY)
;If either is requested, save the background color and initialize
; the function pointer to call the correct function. DCR37
;----------------------------------------------------------------------

        ASSUME  ebx:PDDC
        mov     ebx,pddcDst                              ;EBX->DDC
        cmp     [ebx].ddc_pa.pa_ba.ba_bkmix,BM_DESTTRANSPARENT ;Destination transparent ?
        jne     @f                                       ;If not, check for SRCTRANSPARENT
        mov     bkmix,BM_DESTTRANSPARENT
        mov     al,byte ptr[ebx].ddc_pa.pa_ba.ba_clrBack ;Save background color
        mov     bkclr,al
        jmp     bkmix_known
@@:
        cmp     [ebx].ddc_pa.pa_ba.ba_bkmix,BM_SRCTRANSPARENT  ;Source transparent ?
        jne     @f                                       ;If not, use default
        mov     bkmix,BM_SRCTRANSPARENT
        mov     al,byte ptr[ebx].ddc_pa.pa_ba.ba_clrBack ;Save background color
        mov     bkclr,al
        jmp     bkmix_known
@@:
        mov     bkmix,0
bkmix_known:
        ASSUME  ebx:nothing

;/*
;** Get the source/destination bltting area's vertical/horizontal extents
;*/

        mov     esi,lpParm               ; ptr to stretchblt parameters

        ASSUME  esi:PTR STBLT

        mov     edi,[esi].stb_lpRectl  ; bltting area

        ASSUME  edi:PTR BITBLTPARAMETERS

        mov     eax,[edi].bbp_rclSrc.RECTL.rcl_xLeft
        mov     xSrcOrg,eax
        mov     ebx,[edi].bbp_rclSrc.RECTL.rcl_xRight
        sub     ebx,eax                   ; BX = cxSrcExt = SrcRight - SrcLeft
        mov     eax,[edi].bbp_rclSrc.RECTL.rcl_yBottom
        mov     ySrcOrg,eax
        mov     ecx,[edi].bbp_rclSrc.RECTL.rcl_yTop
        sub     ecx,eax                   ; CX = cySrcExt = SrcTop - SrcBottom

        mov     eax,[edi].bbp_rclTarg.RECTL.rcl_xLeft
        mov     xDstOrg,eax
        mov     edx,[edi].bbp_rclTarg.RECTL.rcl_xRight
        sub     edx,eax                   ; DX = cxDstExt = DstRight - DstLeft
        mov     eax,[edi].bbp_rclTarg.RECTL.rcl_yBottom
        mov     yDstOrg,eax
        mov     eax,[edi].bbp_rclTarg.RECTL.rcl_yTop
        sub     eax,yDstOrg              ; AX = cyDstExt = DstTop - DstBottom

osb_have_extent::

        assert  eax,G,0

        assert  ebx,G,0

        assert  ecx,G,0

        assert  edx,G,0

        mov     cyDstExt,eax
        mov     cxSrcExt,ebx
        mov     cySrcExt,ecx
        mov     cxDstExt,edx

;/*
;** Calculate the initial X/Y error terms and the horizontal DDA Runlength.
;** BX = cxSrcExt, DX = cxDstExt
;** CX = cySrcExt, AX = cyDstExt
;*/

osb_test_yshrink::

        cmp     ecx,eax
        jbe     osb_calc_yerr
        or      fbStBlt,OSB_Y_SHRINK    ;flag if we are vertically compressing
        xchg    ecx,eax

osb_calc_yerr::

        shr     ecx,1                    ;Initial error = MajExt - MinExt/2
        sub     eax,ecx
        mov     cyErrorTerm,eax

osb_test_xshrink::

        mov     ecx,OFFSET SMajorDDARun
        cmp     ebx,edx
        jae     osb_calc_xerr
        xchg    ebx,edx
        mov     ecx,OFFSET DMajorDDARun

osb_calc_xerr::

        shr     edx,1                    ;Initial error = MajExt - MinExt/2
        sub     ebx,edx                   ;BX = initial X error term

;/*
;** Before we calculate the DDA run, we need to transform the starting
;** coordinates of the bltting area from device to screen coordinate.
;*/

osb_xform_origin::

        add     esi,OFFSET STBLT.stb_xSrcDel    ;GS:SI => STBLT.stb_xSrcDel
        lodsd
        add     xSrcOrg,eax
        lodsd
        add     ySrcOrg,eax
        lodsd
        add     xDstOrg,eax
        lodsd
        add     yDstOrg,eax

osb_calc_xdda::

        lea     edi,asDDARun             ;ES:DI => XDDA run array
        call    ecx                      ;calculate the DDA run

;/*
;** Calculate the offset to the start byte in the source bitmap that corresponds
;** to the origin of the clipped source bltting area and the offset to the first
;** pel
;*/

osb_calc_src_offset::

        mov     esi,psdSrc               ;the source surface

        ASSUME  esi:PTR SURFACE

        mov     eax,[esi].sd_pBits    ;the source bitmap
        mov     lpBits,eax

        mov     ebx,[esi].sd_dScan     ;the source scansize
        mov     cbSrcScan,ebx
        mov     eax,[esi].sd_cbScan
        mov     cbSrcPlane,eax           ;the source plane size (mono unused)
        mov     eax,[esi].sd_cy
        sub     eax,ySrcOrg
        dec     eax                      ;flip to HW coordinate

        mul     ebx                      ;AX = offset to start of the scan

        assert  edx,E,0

        add     lpBits,eax
ifndef JFIX        ;IBMJ
        mov     ebx,cxSrcVisPel          ;AX = offset to 1st visible src pel
else         ;IBMJ
        mov     eax,cxSrcVisPel          ;AX = offset to 1st visible src pel
        shr     eax,4
        shl     eax,1                    ;make it word offset
        add     lpBits,eax
        add     npSrcLastScan,eax        ;start from this byte in last scan
        and     cxSrcVisPel,15          ;offset of the 1st pel within word
endif         ;IBMJ

;/*
;** We now need to decide which routine to use to blt each src plane, that is,
;** to use routines for color or monochrome source.
;*/

osb_check_src_color::

        mov     eax,OFFSET XFerColorScan   ;assume color source
        test    [esi].sd_fb,SD_COLOR
        mov     esi,pddcDst                    ;ES:SI => the dest. ddc
        jnz     osb_have_routine        ;check if source is color

;/*
;**  We have a monochrome source, therefore we need to know the destination's
;**  image foreground and background colors for color mapping.
;*/

        ASSUME  esi:PTR DDC

        movzx   eax,[esi].ddc_ia.ia_ba.ba_ipc
        mov     ah,BYTE PTR [esi].ddc_ia.ia_ba.ba_ipcBack.ipc_bClr
        mov     bForeClr,al
        mov     bBackClr,ah
        mov     eax,OFFSET XFerMonoScan
ifndef JFIX        ;IBMJ
        and     cxSrcVisPel,15          ;offset of the 1st pel within word
        shr     ebx,4
        shl     ebx,1                    ;make it word offset
endif         ;IBMJ

osb_have_routine::

        mov     pfnXDDAScan,eax          ;get the right routine
        mov     pfnCopyScan,eax          ;we cannot copy screen-screen until a
ifndef JFIX        ;IBMJ
        add     lpBits,ebx
                                        ;scan is drawn
endif         ;IBMJ

;/*
;** lpBits now points to the word that contains the 1st visible src pel
;** now calculate the address of the start byte in the screen blt area.
;*/

osb_calc_dst_offset::

        mov     esi,[esi].ddc_npsd     ; ES:SI => the dest. surface

        ASSUME  esi:PTR SURFACE

;/*
;** Calculate number of scanlines fix in one bank.
;*/
        xor     edx,edx
        mov     eax,10000h
        mov     ebx,SCREEN_DSCAN
        div     ebx
        mov     ebx,eax
        mov     scan_per_bank,bx        ;Save total scanlines in bank.

;/*
;** Calculate current bank and scanlines left before need to switch bank.
;*/
        mov     cx,bx
        xor     edx,edx
        mov     eax,[esi].sd_cy        ; flip screen's y-coordinate to the
        sub     eax,yDst                 ; hardware convention
        dec     eax                      ; make extents inclusive
        div     ebx
        mov     d_page,al               ;Save current to be blit.
        inc     dx
        mov     dst_scan_line_left,dx   ;Save scanlines left in current bank
        mov     dl,al                   ;Move bank in dl
        call    set_bank_select
                                                ;before need to switch bank.

        mov     cbDstScan,SCREEN_DSCAN  ; destination scan width in bytes
        mov     eax,[esi].sd_cy        ; flip screen's y-coordinate to the
        sub     eax,yDst                 ; hardware convention
        dec     eax                      ; make extents inclusive
        mov     edi,eax                   ; save it for cursor exclusion
        mul     cbDstScan               ; no of bytes in a scan

        assert  edx,E,0

        mov     ebx,xDst                ; get the x origin
        add     eax,ebx                 ; this is the start offset
        movzx   eax,ax
        add     eax,[esi].sd_pBits      ; the screen segment
        mov     lpScreen,eax

;/*
;** Cursor Exclusion for a device destination
;*/

osb_cursor_exclude::

        mov     esi,cxExt
        dec     esi                     ;Make extents inclusive of last point
        mov     ecx,xDst                 ;Set left
        add     esi,ecx                 ;Set right

        mov     edx,cyExt
        neg     edx
        add     edx,edi                   ;DI = top, DX = bottom
        inc     edx                      ;Make DX exclusive

        INVOKE  far_exclude                     ;Exclude the area from the screen

;/*
;** Setup pointers to all the essential data structures.
;*/

osb_set_blt_param::

        lea     esi,asPlaneBuff          ;GS:SI => Plane Buffer
        mov     XSI,esi                  ;put it in the high word
        mov     esi,lpBits               ;the starting pel to blt
        mov     edi,lpScreen             ;the starting pel on screen
        mov     ebx,cyErrorTerm          ;initial y error term

;/*
;** Now we have all the essential information to perform stretchblt. So start
;** munging the bits. Do the DDA in the y direction. For each scan, call
;** XFerOneScan to do the DDA in the X direction.
;*/

osb_start_blt::

        test    fbStBlt,OSB_Y_SHRINK    ;we treat stretching and compressing
        jnz     osb_y_shrink      ;seperately

;/*
;** We are stretching the bitmap vertically. This means, in terms of Y
;** coordinate, destination is the major axis and source is minor. therefore,
;** every source scan will be output to screen. Note that since we may have
;** some destination scan clipped off, we will let the XDDA function decide
;** whether it is going to processthat scan.
;*/

osb_stretch_next_scan::

        call    [pfnXDDAScan]           ;walk along the current src scan
        jz      osb_exit                ;ZF set if all dest scans are processed

osb_stretch_scan_done::

        sub     ebx,cySrcExt             ;subtract minor axis extent
        jge     osb_stretch_copy_scan    ;are we repeating the same scan?
        add     ebx,cyDstExt             ;no! prepare to walk the next scan
        sub     esi,cbSrcScan            ;proceed to the next scan
        jmp     osb_stretch_next_scan


osb_stretch_copy_scan::

        call    [pfnCopyScan]           ;copy the previous scan
        jnz     osb_stretch_scan_done
        jmp     osb_exit

;/*
;** We are compressing the bitmap vertically. This means, in terms of Y
;** coordinate, source is the major axis and destination is minor. therefore,
;** some source scans will be ignored. Note that since we may have
;** some destination scan clipped off, we will let the XDDA function decide
;** whether it is going to processthat scan.
;*/


osb_y_shrink::

        assert  ebx,NE,0                 ;BX = YErrorTerm should not be 0

        call    [pfnXDDAScan]           ;walk along the current src scan
        jz      osb_exit          ;ZF set if all dest scans are processed

osb_elim_next_scan::

        sub     esi,cbSrcScan

osb_elim_this_scan::

        sub     ebx,cyDstExt             ;subtract minor axis extent
        jge     osb_elim_next_scan
        add     ebx,cySrcExt
        call    [pfnXDDAScan]
        jnz     osb_elim_next_scan

;/*
;** now reset the EGA/VGA parameters and bring back the cursor
;*/

osb_exit::
        INVOKE  far_unexclude           ; re-draw the cursor

osb_end::
        RET

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

;/***************************************************************************
;*
;* PUBLIC ROUTINE  SMajorDDARun
;*
;* DESCRIPTION   = This routine calculates a source major DDA run.  the run is
;*                 the sequence of positive number, Ri, representing the interval
;*                 of the source pel for the current, ith, destination pel from
;*                 the previous destination pel.
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX,SI,flags
;*
;* INPUT         = BX = X error term
;*                 ES:DI = address of the DDA run record
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


SMajorDDARun::

;/*
;** First, DDA walk until we find the first source pel corresponds to the
;** first visible pel on the destination.
;*/

        mov     eax,xSrcOrg
        mov     ecx,xDstOrg
        mov     edx,cxSrcExt
        mov     esi,cxDstExt
        cmp     ecx,xDst                 ;enter the visible area?
        je      sa_have_first_src

ifdef   FIREWALLS

        jl      sa_find_first_src

        rip     text,<OEMStretchBlt - xincorrect dst starting coordinates>

endif;  FIREWALLS

;/*
;** In the DDA loop:
;** AX = source x, CX = destination x, BX = error term
;** DX = major axis extent, SI = minor axis extent
;*/

sa_find_first_src::

        inc     eax                      ;step major axis
        sub     ebx,esi                   ;subtract minor axis extent
        jge     sa_find_first_src ;step minor axis?
        add     ebx,edx                   ;yes, add major extent
        inc     ecx                      ;step minor axis
        cmp     ecx,xDst                 ;enter the visible area?
        jl      sa_find_first_src

;/*
;** We now have the offset to the first visible source pel from the unclipped
;** origin, so remember this for address calculation.
;*/

sa_have_first_src::

        mov     cxSrcVisPel,eax          ;offset to the 1st visible pel
        mov     ecx,cxExt

        assert  ecx,G,0

        dec     ecx                      ;we need this # of dst pels
        jz      sa_exit
        xor     eax,eax

;/*
;** In the DDA loop:
;** AX = interval from the last visible source pel
;** CX = # visible dst pels left
;** BX = Error term
;** DX = major axis extent, SI = minor axis extent
;*/

sa_record_run::

        inc     eax                       ;step major axis
        sub     ebx,esi                   ;subtract minor axis extent
        jge     sa_record_run             ;step minor axis?
        add     ebx,edx                   ;yes, add major extent
        stosb                             ;AX = interval between visible pels
        xor     eax,eax                   ;reset the interval
        loop    sa_record_run

sa_exit:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  DMajorDDARun
;*
;* DESCRIPTION   = This routine calculates a source major DDA run.  the run is
;*                 the sequence of positive number, Ri, representing the
;*                 interval of the source pel for the current, ith, destination
;*                 pel from the previous destination pel.
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX,SI,flags
;*
;* INPUT         = BX = X error term
;*                 ES:DI = address of the DDA run record
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


DMajorDDARun::

;/*
;** First, DDA walk until we find the first source pel corresponds to the
;** first visible pel on the destination.
;*/

        mov     eax,xSrcOrg
        mov     ecx,xDstOrg
        mov     edx,cxSrcExt
        mov     esi,cxDstExt

ifdef   FIREWALLS

        cmp     ecx,xDst                 ;enter the visible area?
        jle     da_find_first_src

        rip     text,<OEMStretchBlt - yincorrect dst starting coordinates>

endif;  FIREWALLS

;/*
;** In the DDA loop:
;** AX = source x, CX = destination x, BX = error term
;** DX = minor axis extent, SI = major axis extent
;*/

da_find_first_src::

        cmp     ecx,xDst                 ;enter the visible area?
        je      da_have_first_src
        inc     ecx                      ;step major axis
        sub     ebx,edx                   ;subtract minor axis extent
        jge     da_find_first_src ;step minor axis?
        add     ebx,esi                   ;yes, add major extent
        inc     eax                      ;step minor axis
        jmp     da_find_first_src

;/*
;** We now have the offset to the first visible source pel from the unclipped
;** origin, so remember this for address calculation.
;*/

da_have_first_src::

        mov     cxSrcVisPel,eax          ;offset to the 1st visible pel
        mov     ecx,cxExt                ;we need this # of dst pels
        xor     eax,eax

;/*
;** In the DDA loop:
;** AX = interval from the last visible source pel
;** CX = # visible dst pels left
;** BX = Error term
;** DX = minor axis extent, SI = major axis extent
;*/

        assert  ecx,G,0

da_record_run::

        dec     ecx                      ;step major axis
        jz      da_exit

da_dup_src_pel::

        stosb                           ;assume using the current src pel
        sub     ebx,edx                 ;subtract minor axis extent
        jge     da_record_run           ;step minor axis?
        add     ebx,esi                 ;yes, add major extent
        inc     DWORD PTR [edi][-1]     ;correct assumption--move to next src pel
        ;@DMS i think this  needs to change but dont want to do it now
        ;inc     BYTE PTR [edi][-1]      ;correct assumption--move to next src pel
        loop    da_dup_src_pel

da_exit:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  XFerColorScan
;*
;* DESCRIPTION   = This function performs the stretching/compressing blt
;*                 within one scan, using the information from the
;*                 pre-calculated DDA run record.
;*
;*                 Registers Preserved:
;*                       EBX,SI,DS,ES,GS
;*                 Registers Destroyed:
;*                       AX,CX,DX,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = the 1st visible destination byte
;*                 GS:[ESI.hi] = bitmap buffer
;* OUTPUT        = ES:DI = start of the next destination scan
;*                 ZF      set if no more destination scan to output.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


XFerColorScan::

;/*
;** Check if the current destination scan is clipped off. If so, we can simply
;** ignore this source scan
;*/

        mov     eax,yDstOrg                  ; the current dest. scan
        inc     yDstOrg                     ; update to the next scan
        cmp     eax,yDst                     ; if smaller than 1st visible scan
        jge     @F                    ; then ignore this source scan
        ret
@@:

;/*
;** After we found the first scan the blt, we do not need the testing above
;** anymore. So the following line will be the entry next time it is called.
;*/

        mov     pfnXDDAScan,OFFSET XFerColorScan_Notest
        mov     pfnCopyScan,OFFSET CopyPrevScan

XFerColorScan_Notest::

;/*
;** Initialize transfer loop
;*/

        push    ebx                          ; BX  = cyErrorTerm
        lea     ebx,asDDARun                 ; GS:BX => DDA run records
        call    XFerOneColorPlane
        pop     ebx

        sub     edi,cbDstScan                ; proceed to the next dst scan

        dec     dst_scan_line_left
        jnz     @f
        push    scan_per_bank
        pop     dst_scan_line_left
        dec     d_page
        mov     dl,d_page
        call    set_bank_select
        add     edi,10000h
@@:

        dec     cyExt                       ; one scan was processed

xcs_exit:
        ret

XOP_BYTE_SIZE           equ     8           ; # of bits in one byte
XOP_MOD_WORD_SIZE       equ     15          ; modulo # of bits in one word
XOP_INNER_LOOP_COUNT    equ     8           ; # of inner loop count

;/***************************************************************************
;*
;* PUBLIC ROUTINE  XFerOneColorPlane
;*
;* DESCRIPTION   = This function performs the stretching/compressing blt
;*                 within each plane, using the information from the
;*                 pre-calculated DDA run record.  The processed byte for
;*                 plane 0 are written directly to screen (plane 0), and the
;*                 rest are stored in buffer.
;*
;*                 Registers Preserved:
;*                       ESI,EDI,DS,ES,GS
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = the 1st visible destination byte
;*                 GS:[ESI.hi] = bitmap buffer
;*                 GS:[BX]     = DDA run record
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


XFerOneColorPlane::

        push    esi
        push    edi
        xor     edx,edx
        mov     ch,byte ptr cxSrcVisPel

;/*
;** Transfer a sequence of full middle bytes. (The inner loop has been unwound
;** to optimize the execution speed and codesize.)
;*/

xocp_xfer_full_byte::

        mov     ah,ch
        mov     ecx,cxExt               ; number of full middle bytes
        dec     ecx                     ;make interval inclusive
        or      ecx,ecx
        jz      xocp_xfer_done

        push    ecx
        shr     ecx,2                   ;Prepare to output double word.
        jcxz    no_dword                ;Can we do double word ?
next_double:                            ; 
        push    ecx                     ; 
        mov     ecx,4                   ;Do 4 bytes before out put to screen
do_double:                              ; 
        mov     dl,BYTE PTR [ebx]       ; Get interval to the next offset
        inc     ebx                     ; 
        mov     al,byte ptr [esi]       ; 
        ror     eax,8                   ; 
        add     esi,edx                 ;Advance to next visible source.
        loop    do_double               ; 
        stosd                           ; 
        pop     ecx                     ; 
        loop    next_double             ; 
no_dword:                               ; 
        pop     ecx                     ; 
        and     ecx,3                   ;Set to expand to rest of pixel if any.
        jcxz    xocp_xfer_done          ; 

xocp_xfer_outer_mid_loop::              ; 
        mov     dl,BYTE PTR [ebx]       ; add interval to the next offset
        inc     ebx
        mov     al,byte ptr [esi]
        stosb
        add     esi,edx                 ; advance src pointer
        dec     ecx
        jnz     xocp_xfer_outer_mid_loop

xocp_xfer_done::
        pop     edi
        pop     esi

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE   XFerMonoScan
;*
;* DESCRIPTION   = This function performs the stretching/compressing blt
;*                 within one scan, using the information from the
;*                 pre-calculated DDA run record.
;*
;*                 Registers Preserved:
;*                       EBX,SI,DS,ES,GS
;*                 Registers Destroyed:
;*                       AX,CX,DX,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = the 1st visible destination byte
;* OUTPUT        = ES:DI = start of the next destination scan
;*                 ZF      set if no more destination scan to output.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


XFerMonoScan::

;/*
;** Check if the current destination scan is clipped off. If so, we can simply
;** ignore this source scan
;*/

        mov     eax,yDstOrg                  ; the current dest. scan
        inc     yDstOrg                     ; update to the next scan
        cmp     eax,yDst                     ; if smaller than 1st visible scan
        jge     @F                    ; then ignore this source scan
        ret
@@:

;/*
;** After we found the first scan the blt, we do not need the testing above
;** anymore. So the following line will be the entry next time it is called.
;*/

        mov     pfnXDDAScan,OFFSET XFerMonoScan_Notest
        mov     pfnCopyScan,OFFSET CopyPrevScan

XFerMonoScan_Notest::


;/*
;** Initialize transfer loop
;*/

        push    esi                          ; SI = ptrs to src
        push    ebx                          ; BX = cyErrorTerm
        lea     ebx,asDDARun                 ; GS:BX => DDA run records

xms_setup::

;/*
;** Now, do the stretching/compressing blt directly to screen
;*/

        push    edi
        mov     ah,byte ptr cxSrcVisPel
        mov     edx,(XOP_BYTE_SIZE + XOP_MOD_WORD_SIZE)
        sub     dl,ah                       ; DX = offset from LSB
        and     dl,XOP_MOD_WORD_SIZE


xms_xfer_full_byte::

        mov     ecx,cxExt
        jecxz    xms_xfer_mono_done
        movzx   edx,dl                       ; DH is always 0
        .errnz  XOP_MOD_WORD_SIZE and 0FF00h

xms_xfer_outer_mid_loop::

        push    ecx
        mov     ecx,((XOP_MOD_WORD_SIZE shl 8) + XOP_INNER_LOOP_COUNT)
        xchg    edi,XDI                      ; save DI in its high word

xms_xfer_inner_mid_loop::


        mov     di,WORD PTR [esi]
        mov     al,bForeClr
        bt      di,dx                       ; get the next src pel
        jc      @f
        mov     al,bBackClr
@@:
        and     ah,ch                       ; AH = offset from MSB
        mov     dl,ah
        add     dl,BYTE PTR [ebx]                  ; add interval to the next offset
        inc     ebx
        mov     ah,dl                       ; save the word offset
        shr     edx,4                        ; offset to the next src word
        shl     edx,1
        add     esi,edx                       ; advance src pointer
        mov     edx,(XOP_BYTE_SIZE + XOP_MOD_WORD_SIZE)
        sub     dl,ah                       ; DX = offset from LSB
        and     dl,ch
        xchg    edi,XDI                     ; restore DI
        stosb                               ; write to the destination
        pop     ecx
        dec     ecx
        jnz     xms_xfer_outer_mid_loop


xms_xfer_mono_done::
        pop     edi

        pop     ebx                          ; restore cyErrorTerm
        pop     esi                          ; restore src
        sub     edi,cbDstScan                ; proceed to the next dst scan

        dec     dst_scan_line_left
        jnz     @f
        push    scan_per_bank
        pop     dst_scan_line_left
        dec     d_page
        mov     dl,d_page
        call    set_bank_select
        add     edi,10000h
@@:

        dec     cyExt                       ; one scan was processed

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  CopyPrevScan
;*
;* DESCRIPTION   = This function copies the contents of the previous scan onto
;*                 the current scan.
;*
;*                 Registers Preserved:
;*                       BX,SI,DS,ES,GS
;*                 Registers Destroyed:
;*                       AX,CX,DX,flags
;*
;* INPUT         = DS:SI = the 1st visible source DWORD
;*                 ES:DI = the 1st visible destination byte
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


CopyPrevScan::

        push    ebx
        push    esi
        push    edi

        mov     esi,edi
        add     esi,cbDstScan          ;Point to previous line

        mov     dx,scan_per_bank       ;If scan lines left ==
                                       ; scans per bank, change banks
        cmp     dst_scan_line_left,dx
        mov     dl,d_page
        jnz     @f
        inc     dl
        call    set_bank_select
        sub     esi,10000h
@@:
        push    edi                     ;Save destination address
        mov     ecx,cxExt               ;Get number of bytes to copy
        mov     edi,offset temp_buf     ;Temperary buffer for one scan line
        rep     movsb                   ;Copy to source to temp buffer
        cmp     dl,d_page               ;If switched banks for source
        jz      @f                      ; switch back for destination
        dec     dl
        call    set_bank_select
@@:
        mov     ecx,cxExt               ;Get scan line count
        mov     esi,offset temp_buf     ;Prepare to copy tempary buffer to destination
        pop     edi
        rep     movsb                   ;Copy temp buffer to destination
        pop     edi
        sub     edi,cbDstScan           ;Proceed to the next dst scan
        dec     dst_scan_line_left      ;Switch banks if applicable
        jnz     @f
        push    scan_per_bank
        pop     dst_scan_line_left
        dec     d_page
        mov     dl,d_page
        call    set_bank_select
        add     edi,10000h
@@:
        dec     cyExt                   ;Another line done.

        pop     esi
        pop     ebx

        ret

OEMStretchBlt   ENDP


        public  osb_have_extent
        public  osb_test_yshrink
        public  osb_calc_yerr
        public  osb_test_xshrink
        public  osb_calc_xerr
        public  osb_xform_origin
        public  osb_calc_xdda
        public  osb_calc_src_offset
        public  osb_calc_dst_offset
        public  osb_cursor_exclude
        public  osb_set_blt_param
        public  osb_start_blt
        public  osb_stretch_next_scan
        public  osb_stretch_scan_done
        public  osb_stretch_copy_scan
        public  osb_y_shrink
        public  osb_elim_next_scan
        public  osb_elim_this_scan
        public  osb_exit
        public  sa_find_first_src
        public  sa_have_first_src
        public  sa_record_run
        public  da_find_first_src
        public  da_have_first_src
        public  da_record_run
        public  da_dup_src_pel
        public  xocp_xfer_full_byte
        public  xms_xfer_full_byte

        end
