;*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         07/03/90
;*
;* DESCRIPTION  StretchBlt at level of device driver.     
;*              
;* FUNCTIONS    OEMStretchBlt
;*              osb_Setup8514Rect
;*              SMajorDDARun
;*              DMajorDDARun
;*              XFerOneScan
;*              XFerOneScan_Notest
;*              ShrinkMonoScan
;*              StretchMonoScan
;*              ShrinkColorScan_Pal
;*              StretchColorScan_Pal
;*              ShrinkColorScan_NoPal
;*              StretchColorScan_NoPal
;*              CopyPrevScan
;*
;* 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 
;*
;*****************************************************************************/

        .286P

        .xlist
        include cmacros.inc
INCL_GPIBITMAPS         equ                      1       ; for bitmap info structure
INCL_GPILOGCOLORTABLE   equ                      1
INCL_DDIMISC            equ                      1       ; for BBP structure
        include pmgre.inc
        include driver.inc
        include display.inc
        include 8514.inc
        include oemblt.inc
        include assert.mac
        include palette.inc
        .list

        CPUMode 386

        externFP    far_exclude         ; CURSORSC.ASM
        externFP    far_unexclude       ; CURSORSC.ASM
        externA     DOSHUGEINCR
        externA     DOSHUGESHIFT

sBegin  CompileCodeData
        externB     asDDARun            ; INSTANCE.ASM
sEnd    CompileCodeData

sBegin  Data
        externW     BoardMaxY           ; max real addressable y on board
sEnd

sBegin  PtrData
        externB     screen_busy         ; cursor exclusion flag
sEnd    PtrData

OSB_Y_SHRINK            equ     01h     ; compression in vertical direction
OSB_X_SHRINK            equ     02h     ; compression in horizontal direction
OSB_PALETTE             equ     04h     ; Stretchblt with palette mapping vector
OSB_HUGE_BITMAP         equ     08h     ; huge source bitmap

XOP_BYTE_SIZE           equ     8       ; # of bits in one byte
XOP_MOD_WORD_SIZE       equ     15      ; modulo # of bits in one word
XOP_WORD_SIZE           equ     16      ; # of bits in one word

sBegin  PalSeg
        assumes cs,PalSeg
        assumes ds,nothing
        assumes es,nothing

        externW     PalSegData
        externW     MyCmplPalSegData
        externW     MyPtrPalSegData

;/*
;**   Tables for XDDA transfer routines
;*/

ColorXFer       equ     this word                ; has the color transfer routine addresses
                dw      PalSegOFFSET StretchColorScan_NoPal
                dw      PalSegOFFSET ShrinkColorScan_NoPal
                dw      PalSegOFFSET StretchColorScan_Pal
                dw      PalSegOFFSET ShrinkColorScan_Pal

MonoXFer        equ     this word                ; has the mono transfer routine addresses
                dw      PalSegOFFSET StretchMonoScan
                dw      PalSegOFFSET ShrinkMonoScan

;/***************************************************************************
;*
;* 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
;*
;*                 Calls:
;*                       far_exclude
;*                       far_unexclude
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   OEMStretchBlt,<FAR,PUBLIC,NODATA>,<si,di>

        parmD   pddcDst                           ;Destination ddc
        parmW   xDst                              ;Destination x origin
        parmW   yDst                              ;Destination y origin
        parmD   psdSrc                            ;Source surface definition
        parmD   lpParm                  ;StretchBlt parameters
        parmW   cxExt                             ;x extent of the BLT
        parmW   cyExt                             ;y extent of the BLT
        parmD   pmappal                           ;Source to Dest palette color mapping

        localW  xSrcOrg                           ;source x-origin of the bltting area
        localW  ySrcOrg                           ;source y-origin of the bltting area
        localW  cxSrcExt                          ;source bltting x-extent
        localW  cySrcExt                          ;source bltting y-extent
        localW  xDstOrg                           ;destination x-origin of the bltting area
        localW  yDstOrg                           ;destination y-origin of the bltting area
        localW  cxDstExt                          ;destination bltting x-extent
        localW  cyDstExt                          ;destination bltting y-extent
        localW  yDstCur                 ;the current Y coordinate

        localW  cyErrorTerm             ;the initial Y error term
        localV  abMonoColor,2           ;image foreground/background color

OSB_BACKGROUND      equ     0           ;index to background in abMonoColor
OSB_FOREGROUND      equ     1           ;index to foreground in abMonoColor

        localD  lpBits                  ;ptr to the source bitmap
        localW  selFirstSeg             ;selector of bitmap's 1st segment
        localW  npSrcLastScan           ;offset to the source last scan
        localW  cbSrcScan               ;# of bytes in one src scan
        localW  cxSrcVisPel             ;offset to the first source visible pel
        localB  cxPelinFirstWord        ;# of src pels in the first src word
        localW  cxSrcPel                ;# of source pels stretched to dst pels
        localW  cxSrcPelCnt             ;counter for the transfer loop
        localB  fbStBlt                 ;the stretchblt flag

        localW  pfnXDDA                 ;ptr to the current plane blt function
        localW  pfnXDDAScan             ;ptr to the current scan blt function
        localW  pfnCopyScan             ;ptr to the scan copy function

cBegin

        cld
        mov     fbStBlt,OSB_X_SHRINK; initialize the flag
        xor     eax,eax
        or      eax,pmappal             ;if no palette, pmappal = 0
        jz      short @F
        or      fbStBlt,OSB_PALETTE     ;mark that we have a palette
@@:

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

        lgs     si,lpParm               ; ptr to stretchblt parameters
        assumes gs,nothing
        les     di,gs:[si].stb_lpRectl  ; bltting area
        assumes es,nothing
        mov     ax,es:[di].bbp_rclSrc.rcl_xLeft.lo
        mov     xSrcOrg,ax
        mov     bx,es:[di].bbp_rclSrc.rcl_xRight.lo
        sub     bx,ax                   ; BX = cxSrcExt = SrcRight - SrcLeft
        mov     ax,es:[di].bbp_rclSrc.rcl_yBottom.lo
        mov     ySrcOrg,ax
        mov     cx,es:[di].bbp_rclSrc.rcl_yTop.lo
        sub     cx,ax                   ; CX = cySrcExt = SrcTop - SrcBottom

        mov     ax,es:[di].bbp_rclTarg.rcl_xLeft.lo
        mov     xDstOrg,ax
        mov     dx,es:[di].bbp_rclTarg.rcl_xRight.lo
        sub     dx,ax                   ; DX = cxDstExt = DstRight - DstLeft
        mov     ax,es:[di].bbp_rclTarg.rcl_yBottom.lo
        mov     yDstOrg,ax
        mov     ax,es:[di].bbp_rclTarg.rcl_yTop.lo
        sub     ax,yDstOrg              ; AX = cyDstExt = DstTop - DstBottom

osb_have_extent:
        assert  ax,G,0
        assert  bx,G,0
        assert  cx,G,0
        assert  dx,G,0
        mov     cyDstExt,ax
        mov     cxSrcExt,bx
        mov     cySrcExt,cx
        mov     cxDstExt,dx

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

osb_test_yshrink:
        cmp     cx,ax
        jbe     short osb_calc_yerr
        or      fbStBlt,OSB_Y_SHRINK    ;flag if we are vertically compressing
        xchg    cx,ax

osb_calc_yerr:
        shr     cx,1                    ;Initial error = MajExt - MinExt/2
        sub     ax,cx
        mov     cyErrorTerm,ax

osb_test_xshrink:
        mov     cx,PalSegOFFSET SMajorDDARun
        cmp     bx,dx
        jae     short osb_calc_xerr
        xchg    bx,dx
        mov     cx,PalSegOFFSET DMajorDDARun
        and     fbStBlt,not OSB_X_SHRINK;clear flag if we horizontally stretch

osb_calc_xerr:
        shr     dx,1                    ;Initial error = MajExt - MinExt/2
        sub     bx,dx                   ;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 coordinates.
;*/

osb_xform_origin:
        add     si,stb_xSrcDel          ;GS:SI => STBLT.stb_xSrcDel
        lods    word ptr gs:[si]
        add     xSrcOrg,ax
        lods    word ptr gs:[si]
        add     ySrcOrg,ax
        lods    word ptr gs:[si]
        add     xDstOrg,ax
        lods    word ptr gs:[si]
        add     yDstOrg,ax

osb_calc_xdda:
        mov     es,MyCmplPalSegData
        assumes es,nothing
        lea     di,asDDARun             ;ES:DI => XDDA run array
        cCall   cx                      ;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:
        les     si,psdSrc               ;the source surface
        assumes es,nothing
        mov     eax,es:[si].sd_pBits    ;the source bitmap
        mov     lpBits,eax
        shr     eax,16                  ;remember the first segment
        mov     selFirstSeg,ax

        mov     bx,es:[si].sd_dScan     ;the source scansize
        mov     cbSrcScan,bx
        mov     ax,es:[si].sd_cy
        sub     ax,ySrcOrg
        dec     ax                      ;flip to HW coordinates
        test    es:[si].sd_fb,SD_HUGE   ;if the bitmap is not huge
        jz      short @F                ;we already have the scan number
        or      fbStBlt,OSB_HUGE_BITMAP
        xor     dx,dx
        div     es:[si].sd_cySeg        ;find the segment where it is in
        mov     cx,DOSHUGESHIFT         ;FATAL!! DOSHUGESHFT will overwrite
        shl     ax,cl                   ;next instruction if use with shl
        add     lpBits.sel,ax           ;advance to the correct segment
        mov     ax,es:[si].sd_cbFill
        add     ax,bx                   ;BX = scansize
        neg     ax
        mov     npSrcLastScan,ax        ;offset to the last scan in a segment
        mov     ax,dx                   ;DX = number of scans in a segment
@@:
        mul     bx                      ;AX = offset to start of the scan
        assert  dx,E,0                  ;the offset should not > 64K
        add     lpBits.off,ax

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

osb_check_src_color:
        mov     ax,cxSrcVisPel          ;AX = offset to 1st visible src pel
        movzx   bx,fbStBlt
        and     bx,OSB_PALETTE+OSB_X_SHRINK;BX = index into the xdda transfer table
        .errnz  OSB_X_SHRINK - 2
        .errnz  OSB_PALETTE - 4
        mov     dx,ColorXFer[bx]        ;assume color source => color routines
        test    es:[si].sd_fb,SD_COLOR
        les     si,pddcDst              ;ES:SI => the dest. ddc
        assumes es,nothing
        jnz     short 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 mapping them to 0/1 pels.
;**  Moreover, we need to know the offset of the first visible bit within the
;**  1st visible byte of the monochrome bitmap.
;*/

        mov     cl,es:[si].ddc_pa.pa_ba.ba_ipc.ipc_bClr    ; fetch fg color
        mov     abMonoColor[OSB_FOREGROUND],cl
        mov     cl,es:[si].ddc_pa.pa_ba.ba_ipcBack.ipc_bClr; fetch bg color
        mov     abMonoColor[OSB_BACKGROUND],cl
        shr     ax,4                    ;AX = offset to 1st visible src pel
        shl     ax,1                    ;make it word offset
        mov     cx,cxSrcVisPel
        and     cx,XOP_MOD_WORD_SIZE    ;offset of the 1st pel within word
        mov     cxSrcVisPel,cx
        neg     cx
        add     cx,XOP_WORD_SIZE        ;# of bits from the visible pels
        cmp     cxSrcPel,cx             ;test if only within 1st word
        jge     short @F
        mov     cx,cxSrcPel
@@:
        mov     cxPelinFirstWord,cl     ;only this # of pels needed from 1st word
        and     bx,not OSB_PALETTE      ;monochrome ignores palette
        mov     dx,MonoXFer[bx]         ;routine for stretch/compress

osb_have_routine:
        mov     pfnXDDA,dx              ;get the right routine
        add     lpBits.off,ax           ;add the contribution of the starting
        add     npSrcLastScan,ax        ;byte to the scan info
        mov     ax,PalSegOFFSET XFerOneScan
        mov     pfnXDDAScan,ax
        mov     pfnCopyScan,ax

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

osb_cursor_exclude:
        mov     si,es:[si].ddc_npsd     ;ES:SI => the dest. surface
        mov     di,es:[si].sd_cy        ;flip screen's y-coordinate to the
        sub     di,yDst                 ;hardware convention
        mov     dx,di                   ;save this exclusive value
        dec     di                      ;make extents inclusive
        mov     yDstCur,di              ;mark the first scan
        sub     dx,cyExt                ;DI = top, DX = bottom

        mov     si,cxExt
        dec     si                                ;Make extents inclusive of last point
        mov     cx,xDst                 ;Set left
        add     si,cx                             ;Set right
        cCall   far_exclude                       ;Exclude the area from the screen

;/*
;** Setup the screen parameters.
;*/

osb_set_up_screen:
        GrabScreen  OEMStretchBlt,FAR,PalSeg; don't let cursor operations kill us
        cCall   osb_Setup8514Rect                ; set dimensions, issue write command

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

osb_set_blt_param:
        lds     si,lpBits               ;the starting pel to blt
        assumes ds,nothing
        mov     es,MyCmplPalSegData     ;for DDA run buffer
        assumes es,nothing
        lea     di,asDDARun             ;ES:DI => DDA run buffer
        mov     gs,pmappal.sel          ;palette mapping vector
        assumes gs,nothing
        mov     bx,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     short 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:
        cCall   [pfnXDDAScan]           ;walk along the current src scan
        jz      osb_exit                ;ZF set if all dest scans are processed

osb_stretch_scan_done:
        sub     bx,cySrcExt             ;subtract minor axis extent
        jge     short osb_stretch_copy_scan;are we repeating the same scan?
        add     bx,cyDstExt             ;no! prepare to walk the next scan
        sub     si,cbSrcScan            ;proceed to the next scan
        jnc     short osb_stretch_next_scan

osb_stretch_new_seg:

ifdef   FIREWALLS
        test    fbStBlt,OSB_HUGE_BITMAP
        jnz     short @F
        rip     text,<OEMStretchBlt - updating selector of a small bitmap>
@@:
endif;  FIREWALLS

        mov     ax,ds
        sub     ax,DOSHUGEINCR          ;upto previous scan
        cmp     ax,selFirstSeg          ;this could happen only once
        jb      short osb_stretch_dup_last
        mov     ds,ax
        assumes ds,nothing
        mov     si,npSrcLastScan        ;offset to the last scan in segment
        jmp     short osb_stretch_next_scan

osb_stretch_dup_last:
        add     si,cbSrcScan
        jmp     short osb_stretch_next_scan

osb_stretch_copy_scan:
        cCall   [pfnCopyScan]           ;copy the previous scan
        jnz     short osb_stretch_scan_done
        jmp     short 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_shrink_new_seg:

ifdef   FIREWALLS
        test    fbStBlt,OSB_HUGE_BITMAP
        jnz     short @F
        rip     text,<OEMStretchBlt - updating selector of a small bitmap>
@@:
endif;  FIREWALLS

        mov     ax,ds
        sub     ax,DOSHUGEINCR          ;upto previous scan
        cmp     ax,selFirstSeg          ;this could happen only once
        jb      short osb_shrink_dup_last
        mov     ds,ax
        assumes ds,nothing
        mov     si,npSrcLastScan        ;offset to the last scan in segment
        jmp     short osb_elim_this_scan

osb_shrink_dup_last:
        add     si,cbSrcScan
        jmp     short osb_elim_this_scan

osb_y_shrink:
        assert  bx,NE,0                 ;BX = YErrorTerm should not be 0
        cCall   [pfnXDDAScan]           ;walk along the current src scan
        jz      short osb_exit          ;ZF set if all dest scans are processed

osb_elim_next_scan:
        sub     si,cbSrcScan
        jc      short osb_shrink_new_seg

osb_elim_this_scan:
        sub     bx,cyDstExt             ;subtract minor axis extent
        jge     short osb_elim_next_scan
        add     bx,cySrcExt
        cCall   [pfnXDDAScan]
        jnz     short osb_elim_next_scan

;/*
;** now reset the 8514 parameters and bring back the cursor
;*/

osb_exit:
        ReleaseScreen OEMStretchBlt,FAR,PalSeg;allow cursor to do what it has to
        cCall   far_unexclude                     ; re-draw the cursor

osb_end:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  osb_Setup8514Rect
;*
;* DESCRIPTION   = This routine sets the 8514's X, Y, DX, and DY registers to   
;*                 the dimensions of the rectangle to be drawn.  Checks that    
;*                 FIFO has enough room to accept incomming data                
;*
;*                 Registers Destroyed:                                                                      
;*                       AX,DX,flags                                                                   
;*
;* INPUT         = BX = X error term                     
;*                 ES:DI = address of the DDA run record 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   osb_Setup8514Rect, <NEAR, PUBLIC, NODATA>
cBegin

;/*
;** Since our source and destination have already been pre-clipped we do not
;** have to worry about GP faults locally or coordinate wrap on the board.
;** Therefore, we set up the board clip rectangle here so that it need not
;** be done anywhere in the loop.
;**
;** In addition, we can assume that we are always writing to/from all planes,
;** since PM doesn't seem to utilize plane enable as a concept, and we do not
;** use it in the blt. Therefore, go ahead and enable all planes for reading
;** and / or writing.
;*/

        WaitQ   6                       ; set up scissor rectangle
        Mov     Ax,xDst                 ; min left x
        Or      Ah,High XMIN_2DECODE
        .errnz  Low XMIN_2DECODE
        outwQ   XMIN                    ; x clip bounds is clipped rect bounds
        And     Ah,Not (High DECODE_FIELD)
        .errnz  Low DECODE_FIELD
        Add     Ax,cxExt                ; max right x
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX
        outwQ   YMIN,YMIN_2DECODE       ; min y is always 0

        mov     ds,PalSegData
        assumes ds,Data
        mov     ax,ds:BoardMaxY         ; maximum display area height

        Or      Ah,High YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX
        Mov     Al,0ffh                 ; all planes enabled for r/w
        outbQ   READ_ENABLE,Al
        outbQ   WRITE_ENABLE,Al

;/*
;** Set X and Y extents
;*/

        WaitQ   2
        mov     ax,cxExt                ; output a full scan
        dec     ax
        outwQ   LX
        xor     ax,ax                   ; output one scan at a time
        outwQ   LY

cEnd

;/***************************************************************************
;*
;* 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.                                 
;*
;*                 Warning:
;*                       Use frames from OEMStretchBlt
;*
;*                 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
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   SMajorDDARun,<PUBLIC,NEAR,NODATA>

cBegin

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

        mov     ax,xSrcOrg
        mov     cx,xDstOrg
        mov     dx,cxSrcExt
        mov     si,cxDstExt
        cmp     cx,xDst                 ;enter the visible area?
        je      short sa_have_first_src

ifdef   FIREWALLS
        jl      short sa_find_first_src
        rip     text,<OEMStretchBlt - incorrect 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     ax                      ;step major axis
        sub     bx,si                   ;subtract minor axis extent
        jge     short sa_find_first_src ;step minor axis?
        add     bx,dx                   ;yes, add major extent
        inc     cx                      ;step minor axis
        cmp     cx,xDst                 ;enter the visible area?
        jl      short 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,ax          ;offset to the 1st visible pel
        mov     cx,cxExt
        assert  cx,G,0
        dec     cx                      ;we need this # of dst pels
        jz      short sa_exit
        xor     ax,ax

;/*
;** 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     ax                      ;step major axis
        sub     bx,si                   ;subtract minor axis extent
        jge     short sa_record_run     ;step minor axis?
        add     bx,dx                   ;yes, add major extent
        stosw                           ;AX = interval between visible pels
        xor     ax,ax                   ;reset the interval
        loop    sa_record_run

sa_exit:
cEnd

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

        assumes ds,nothing
        assumes es,nothing

cProc   DMajorDDARun,<PUBLIC,NEAR,NODATA>

cBegin

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

        mov     ax,xSrcOrg
        mov     cx,xDstOrg
        mov     dx,cxSrcExt
        mov     si,cxDstExt

ifdef   FIREWALLS
        cmp     cx,xDst                 ;enter the visible area?
        jle     short da_find_first_src
        rip     text,<OEMStretchBlt - incorrect 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     cx,xDst                 ;enter the visible area?
        je      short da_have_first_src
        inc     cx                      ;step major axis
        sub     bx,dx                   ;subtract minor axis extent
        jge     short da_find_first_src ;step minor axis?
        add     bx,si                   ;yes, add major extent
        inc     ax                      ;step minor axis
        jmp     short 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,ax          ;offset to the 1st visible pel
        mov     cx,cxExt                ;we need this # of dst pels
        xor     ax,ax
        push    di

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

        assert  cx,G,0

da_record_run:
        dec     cx                      ;step major axis
        jz      short da_last_pel

da_dup_src_pel:
        inc     ax
        sub     bx,dx                   ;subtract minor axis extent
        jge     short da_record_run     ;step minor axis?
        add     bx,si                   ;yes, add major extent
        stosw
        xor     ax,ax
        loop    da_dup_src_pel

da_last_pel:
        inc     ax                      ;include the last dst pel
        stosw
        add     si,ax

da_exit:
        pop     dx
        sub     di,dx                   ;DI = # of bytes in DDA run
        shr     di,1                    ;DI = # of words in DDA run
        mov     cxSrcPel,di             ;which equals # of src pels involved

cEnd

;/***************************************************************************
;*
;* 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:
;*                       BX,SI,DS,ES,GS
;*                 Registers Destroyed:
;*                       AX,CX,DX,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD     
;*                 ES:DI = DDA Run records
;*                 GS    = selector of the pallette mapping vector
;* OUTPUT        = ZF      set if no more destination scan to output. 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   XFerOneScan,<PUBLIC,NEAR,NODATA>

cBegin  <nogen>

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

        mov     ax,yDstOrg                  ; the current dest. scan
        inc     yDstOrg                     ; update to the next scan
        cmp     ax,yDst                     ; if smaller than 1st visible scan
        jge     short @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,PalSegOFFSET XFerOneScan_Notest
        mov     pfnCopyScan,PalSegOFFSET CopyPrevScan

cEnd    <nogen>

cProc   XFerOneScan_Notest,<PUBLIC,NEAR,NODATA>,<bx,si,di>

cBegin


;/*
;** Set mode to host supplied data
;*/

        WaitQ   5                           ; let use wait until the queue
        outwQ   MODE,MODE_2DECODE+MD_PS_ONES; is empty from scan copy

;/*
;** Set the forground mix register to source-copy with host supplied data
;*/

        outwQ   FUNCTION_1,FUNC_2OP_VAR+FUNC_S

;/*
;** Set X and Y origin and X-extent
;*/

        outwQ   X0,xDst                     ; rectangle's left hand side
        outwQ   Y0,yDstCur                  ; the current scan

CMDCOLOR        =       (\
                         CMD_C_HRECT+CMD_BYTEORDER+CMD_FV_VAR+CMD_DY+\
                         CMD_DX+CMD_MA_ACCESS+CMD_PA_ONE+CMD_RW_W\
                        )

;/*
;** Make sure there is enough room for 1st data item on top of write command
;** befare issue proper write command
;*/

        outwQ   CMD_FLAGS,CMDCOLOR

        WaitQOUT                            ; wait for the empty queue
        cCall   [pfnXDDA]                   ; call the actual transfer routine
        dec     yDstCur                     ; update current Y position
        dec     cyExt                       ; one scan was processed

xos_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ShrinkMonoScan
;*
;* DESCRIPTION   = This function performs the compressing blt within one        
;*                 monochrome scan, using the information from the              
;*                 pre-calculated DDA run record.  This function performs the   
;*                 compressing blt within one monochrome scan, using the        
;*                 information from the pre-calculated DDA run record.          
;*                                                                              
;*                 Registers Preserved:                      
;*                       DS,ES,GS                
;*                 Registers Destroyed:                      
;*                       AX,BX,CX,DX,SI,DI,flags             
;*
;* INPUT         = DS:SI = the 1st visible source WORD            
                   ES:DI = DDA Run records
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   ShrinkMonoScan,<PUBLIC,NEAR,NODATA>

cBegin

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

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

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     cx,cxExt                    ; the number of src pel involved
        assert  cx,G,0

xkm_xfer_loop:
        mov     bx,ds:[si]
        bt      bx,dx                       ; get the next src pel
        lea     bx,abMonoColor              ; CY = 1 => src pel is foreground
        adc     bx,0                        ; otherwise src pel is background
        mov     al,ss:[bx]                  ; AL = foreground/background color
        ror     edx,16                      ; DX = 8514 port
        out     dx,ax
        ror     edx,16                      ; DX = source bit offset

        and     ah,XOP_MOD_WORD_SIZE        ; AH = offset from MSB
        mov     dl,ah
        add     dx,es:[di]                  ; add interval to the next offset
        add     di,2
        mov     ah,dl                       ; save the word offset
        shr     dx,4                        ; offset to the next src word
        shl     dx,1
        add     si,dx                       ; advance src pointer
        mov     dx,(XOP_BYTE_SIZE + XOP_MOD_WORD_SIZE)
        sub     dl,ah                       ; DX = offset from LSB
        and     dl,XOP_MOD_WORD_SIZE
        loop    xkm_xfer_loop

xkm_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  StretchMonoScan
;*
;* DESCRIPTION   = This function performs the stretching blt within one         
;*                 monochrome scan, using the information from the              
;*                 pre-calculated DDA run record.                               
;*
;*                 Registers Preserved:                      
;*                       DS,ES,GS                
;*                 Registers Destroyed:                      
;*                       AX,BX,CX,DX,SI,DI,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
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   StretchMonoScan,<PUBLIC,NEAR,NODATA>

cBegin

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

        mov     dx,COLOR_1                  ; the 8514 port
        mov     ah,cxPelinFirstWord         ; count of the number pel in first word
        ror     eax,16
        lodsw                               ; the first source word
        xchg    al,ah                       ; put it in the correct order
        mov     cl,byte ptr cxSrcVisPel     ; offset to the first visible pel
        shl     ax,cl                       ; shift the first pel to MSB

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     cx,cxSrcPel                 ; the number of src pel involved
        assert  cx,G,0

xsm_xfer_loop:
        shl     ax,1                        ; CY = the next source bit
        lea     bx,abMonoColor              ; CY = 1 => src pel is foreground
        adc     bx,0                        ; otherwise src pel is background
        ror     eax,16                      ; save the source word in high word
        mov     al,ss:[bx]                  ; AL = fore/background color
        mov     bx,es:[di]                  ; # of duplicated dst pels
        add     di,2                        ; move to the next source pel

xsm_out_loop:
        out     dx,ax                       ; duplicate the source pel
        dec     bx
        jnz     short xsm_out_loop
        dec     ah                          ; one src pel is duplicated
        ror     eax,16                      ; AX = source word
        loopne  xsm_xfer_loop               ; next src pel if valid fetched word
        jcxz    xsm_exit                    ; done if no more src pel
        lodsw
        xchg    al,ah                       ; put them in the right order
        or      eax,(16 shl 24)             ; put 16 in the highest byte
        jmp     short xsm_xfer_loop

xsm_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ShrinkColorScan_Pal
;*
;* DESCRIPTION   = This function performs the compressing blt within one color  
;*                 scan, using the information from the pre-calculated DDA run  
;*                 record.  It also performs color mapping from source to       
;*                 destination via the palette mapping table.                   
;*
;*                 Registers Preserved:                                                              
;*                       BX,DI,DS,ES,GS                                                              
;*                 Registers Destroyed:  
;*                       AX,CX,DX,flags  
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = DDA Run records
;*                 GS    = selector of the palette mapping vector
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   ShrinkColorScan_Pal,<PUBLIC,NEAR,NODATA>

cBegin

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     bx,pmappal.off              ; GS:BX => palette mapping vector
        mov     cx,cxExt                    ; the number of dst pel involved
        assert  cx,G,0
        mov     dx,COLOR_1

xkcp_xfer_loop:
        mov     al,ds:[si]                  ; the src pel
        xlat    gs:[bx]                     ; look up the color
        out     dx,ax
        add     si,es:[di]                  ; skip some pels
        add     di,2                        ; next DDA record
        loop    xkcp_xfer_loop

xkcp_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  StretchColorScan_Pal
;*
;* DESCRIPTION   = This function performs the stretching blt within one color 
;*                 scan, using the information from the pre-calculated DDA run
;*                 record.  It also performs color mapping from source to     
;*                 destination via the palette mapping table.                 
;*
;*                 Registers Preserved:                                                              
;*                       DS,ES,GS                                                              
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,SI,DI,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = DDA Run records
;*                 GS    = selector of the palette mapping vector
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   StretchColorScan_Pal,<PUBLIC,NEAR,NODATA>

cBegin

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     bx,pmappal.off              ; GS:BX => palette mapping vector
        mov     cx,cxSrcPel                 ; the number of src pel involved
        assert  cx,G,0
        mov     cxSrcPelCnt,cx              ; initialize the loop counter
        mov     dx,COLOR_1

xscp_xfer_loop:
        lodsb                               ; the src pel
        xlat    gs:[bx]                     ; look up the color
        mov     cx,es:[di]                  ; # of duplicated dst pels

xscp_out_loop:
        out     dx,ax                       ; duplicate the source pel
        loop    xscp_out_loop
        add     di,2                        ; move to the next source pel
        dec     cxSrcPelCnt
        jnz     short xscp_xfer_loop

xscp_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ShrinkColorScan_NoPal
;*
;* DESCRIPTION   = This function performs the compressing blt within one        
;*                 monochrome scan, using the information from the              
;*                 pre-calculated DDA run record.  No color conversion from     
;*                 source to destination is performed.                          
;*
;*                 Registers Preserved:                                                              
;*                       BX,DI,DS,ES,GS                                                              
;*                 Registers Destroyed:  
;*                       AX,CX,DX,flags  
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = DDA Run records
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/



        assumes ds,nothing
        assumes es,nothing

cProc   ShrinkColorScan_NoPal,<PUBLIC,NEAR,NODATA>

cBegin

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     cx,cxExt                    ; the number of dst pel involved
        assert  cx,G,0
        mov     dx,COLOR_1

xkc_xfer_loop:
        mov     al,ds:[si]                  ; the src pel
        out     dx,ax
        add     si,es:[di]                  ; skip some pels
        add     di,2                        ; next DDA record
        loop    xkc_xfer_loop

xkc_exit:
cEnd

;/***************************************************************************
;*
;* PUBLIC ROUTINE  StretchColorScan_NoPal
;*
;* DESCRIPTION   = This function performs the stretching blt within one         
;*                 monochrome scan, using the information from the              
;*                 pre-calculated DDA run record.  No color conversion from     
;*                 source to destination is performed.                          
;*
;*                 Registers Preserved:                                                              
;*                       DS,ES,GS                                                              
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,SI,DI,flags
;*
;* INPUT         = DS:SI = the 1st visible source WORD
;*                 ES:DI = DDA Run records
;*
;* OUTPUT        = ZF      set if no more destination scan to output. 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   StretchColorScan_NoPal,<PUBLIC,NEAR,NODATA>

cBegin

;/*
;** Transfer a sequence of full bytes.
;*/

        mov     cx,cxSrcPel                 ; the number of src pel involved
        assert  cx,G,0
        mov     cxSrcPelCnt,cx              ; initialize the loop counter
        mov     dx,COLOR_1

xsc_xfer_loop:
        lodsb                               ; the src pel
        mov     cx,es:[di]                  ; # of duplicated dst pels

xsc_out_loop:
        out     dx,ax                       ; duplicate the source pel
        loop    xsc_out_loop
        add     di,2                        ; move to the next source pel
        dec     cxSrcPelCnt
        jnz     short xsc_xfer_loop

xsc_exit:
cEnd

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

        assumes ds,nothing
        assumes es,nothing

cProc   CopyPrevScan,<PUBLIC,NEAR,NODATA>

cBegin

;/*
;** Set mode to host supplied data
;*/

        WaitQ   7
        outwQ   MODE,MODE_2DECODE+MD_PS_ONES

;/*
;** Set the forground mix register to source-copy with copy rectangle
;*/

        outwQ   FUNCTION_1,FUNC_2OP_COPY+FUNC_S

;/*
;** Reset X and Y origin to the source scan line which is the scan right below
;** the current position
;*/

        outwQ   X1,xDst                     ; always start at the left hand side
        outwQ   X0
        outwQ   Y1,yDstCur                  ; the current Y is destination scan
        inc     ax
        outwQ   Y0                          ; the previous Y is source scan

CMDSRCSCR       =       (\
                         CMD_C_CRECT+CMD_FV_FIX+CMD_PA_FOUR+CMD_DX+CMD_DY+\
                         CMD_MA_ACCESS+CMD_RW_W\
                        )

        outwQ   CMD_FLAGS,CMDSRCSCR         ; copy the previous scan

        dec     yDstCur                     ; update current Y position
        dec     cyExt                       ; one scan was processed

xcp_exit:
cEnd

sEnd    PalSeg

        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_check_src_color
        public  osb_have_routine
        public  osb_cursor_exclude
        public  osb_set_up_screen
        public  osb_set_blt_param
        public  osb_start_blt
        public  osb_stretch_next_scan
        public  osb_stretch_scan_done
        public  osb_stretch_new_seg
        public  osb_stretch_dup_last
        public  osb_stretch_copy_scan
        public  osb_shrink_new_seg
        public  osb_shrink_dup_last
        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

        end
