;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page ,132
;***********************************************************************
;
;   Module          = EDDHAVIO
;
;   Description     = Private AI code
;
;   Function        = Does AVIO text work
;
;
;   Change log:
;   Date      Mark         APAR      Description
;   --------  ------------ --------- -----------------------------------
;   08/18/93                         Fix incorrect fonts display when
;                                    LCID not = 0
;   09/01/93               73052     Set cursor destination within clip
;                                    loop for 8514.
;   02/11/94  @78461                 It is possible the the default font table is trash,
;                                    so return an error to get it reloaded
;
;***********************************************************************

INCL_GPIBITMAPS EQU     1
INCL_FONTFILEFORMAT     equ     1       ; to include pmfont.inc
include os2.inc
include eddinclt.inc

include eddhcone.inc
include eddhmacr.inc
include eddhtype.inc

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

ifdef _8514
include 8514.inc
endif

ifdef MATROX
extrn _ShadowXGARegs    :dword

; The movxga macro in slightly inappropriate here, so we redefine it as
; the simplest way of doing things.
movxga  macro   address
        lea     esi, _ShadowXGARegs
        endm
endif ; MATROX


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

; External access for this module

AIxfer equ <_AIxfer>

ifndef  _8514
extrn _pRealXGARegs     :dword
else
extrn _pReal8514Regs    :dword
ifdef BPP24
extrn _Shadow8514Regs    :dword
extrn _CouldntCache    :dword
extrn _Copy24MonoToVRAM    :NEAR
endif
extrn _DDT              :byte
endif
extrn AIxfer            :dword
extrn _pAVIOColorXlate  :dword
extrn _SPad             :dword
extrn _pCurCacheBasePhy :dword
extrn _pbHWPollRegister :dword

extrn  _eddt_CacheCharacter     :PROC
extrn  _eddt_LocateCachedFont   :PROC
extrn  _eddt_TidyUpAfterCaching :PROC

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

; Constants

; Avio exteneded attribute masks
MFI_REV_VIDEO   equ 00400000h
MFI_TRANSPARENT equ 00100000h
MFI_USCORE      equ 00800000h
;MFI_OSTRIKE     equ 00200000h  ; Austin now use this bit for something else
                                ; so we now need MFI_OSTRIKE to be 0
MFI_OSTRIKE     equ 00000000h

MFI_FONTBITS    equ 03h         ; Mask for font bits (after shifting)

MFI_CHARMASK    equ 000300ffh   ; Mask to remove attributes

OVERPAINT       equ 03h
LEAVE_ALONE     equ 05h
INVERT_DEST     equ 0Ah

AVIO_usblt      equ 08018040h

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

; Parameter block

AVIOPB          struc
bColumn             db      ?
bRow                db      ?
bAcross             db      ?
bDown               db      ?
pLVBChars           dd      ?
bBufferWidth        db      ?
bSourceColumn       db      ?
bSourceRow          db      ?
bDestColumn         db      ?
bDestRow            db      ?
cClipRects          dw      ?
pFirstClipRect      dd      ?                                           ;**
pCurrentClipRect    dd      ?                                           ;**
usCursorX           dw      ?
usCursorY           dw      ?
usCursorH           dw      ?
usCursorL           dw      ?
pbmhDest            dd      ?                                           ;**

; These next fields are not present in the C version of this structure
; and should really be local variables rather than in this block

bFGIndex            db      ?           ; these are VIO indices - ie 0 -> 15
bBGIndex            db      ?           ;    "
sXPosition          dw      ?           ; designated SHORT but may be unsigned ?
sYPosition          dw      ?           ;    "
sRowPosition        dw      ?           ;    "
usXSource           dw      ?
usYSource           dw      ?
usXDest             dw      ?
usYDest             dw      ?


AVIOPB          ends

; Scratch pad block

AVIOSP          struc
clipx0          dw      ?
clipx1          dw      ?
clipy0          dw      ?
clipy1          dw      ?
fontnum         db      ?
currfontbase    dd      ?
unlockcount     dw      ?
unlockhandle    dd      ?
lockcount       dw      ?
lockpointer     dd      ?
lockheader      dd      ?
AVIOSP          ends

MAX_NUM_CODEPOINTS      equ   256

FontCacheInfo           struc
fci_fmFontMetrics         DB      SIZE FOCAMETRICS DUP (?)
fci_usHashMetrics         DW      (?)
fci_usUsageCount          DW      (?)
fci_usFontId              DW      (?)
fci_usCodePage            DW      (?)
fci_aulCachedCharOffset   DD      MAX_NUM_CODEPOINTS DUP (?)
ifdef FULL_ADDRESS
fci_apCharDef             DD      MAX_NUM_CODEPOINTS DUP (?)
else ; ndef FULL_ADDRESS
fci_apCharDef             DW      MAX_NUM_CODEPOINTS DUP (?)
endif ; ndef FULL_ADDRESS
fci_ausFontPlaneOffset    DW      MAX_NUM_CODEPOINTS DUP (?)
FontCacheInfo           ends

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

_DATA           segment dword use32 public 'DATA'                       ;**
_DATA           ends

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

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

IFNDEF _8514

;***********************************************************************
;
; Function: CGATextBlock - XGA Version
;
; Called by: eddv*.c modules (charrect, charstr, scrollrect)
;
; This code draws a block of CGA text into all the current clip
; rectangles.  It is arranged like this..
;       FOR each clip rectangle
;               FOR each character
;                       draw character into clip rectangle
;  ..so that we can do some elimination of characters because we know
; that the block will always be printed from top left to bottom right.
;
; This code is 386 only.
;
;***********************************************************************
; AK new version
; assumes all chars are cached in VRAM (or wherever).
; This is all the base font - no changes of font occur
;***********************************************************************

        align   4
cProc CGATextBlock,<PUBLIC>,<edi,esi,ebx>
        parmD   pFontDetails
        parmD   pAvioInfo
        localD  chcount
        localD  mask_org_store

cBegin
        pushxga

; Are there any characters to print?
        cmp     AIxfer.bAcross, 0
        je      short no_chars
        cmp     AIxfer.bDown, 0
        jne     short some_chars

no_chars:
; Nothing here for us to do so quit
        jmp     pmcgaexit

some_chars:

; Something to do so do some set-up
; Get the base of the memory mapped registers and the codepage table
        mov     edi, pAvioInfo
        ifndef  _8514
        movxga  _pRealXGARegs
        else
        movxga  _pReal8514Regs
        endif

; Set up the destination bitmap (will be the screen)
        waitshort

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; physical address
        mov     eax, [ebx].phys_addr
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     eax, dword ptr [ebx].hw_width   ; get width and height !
        .erre   hw_height eq (hw_width + 2)
        memregwrite     pi_map_size_A, eax

; format
        mov     al, byte ptr [ebx].hw_format
        memregwrite     pi_map_format_A, al

; Invalidate the previous colour store (nb. writes to both fg and bg)
        mov     ax, 0FFFFh
        mov     word ptr AIxfer.bFGIndex, ax
        .erre   bBGIndex eq (bFGIndex + 1)

; Do some set up here which only needs to be done once
; AVIO CGA text WILL overpaint
        memregwrite     fg_mix, 03h
        memregwrite     bg_mix, 03h
        memregwrite     colour_comp_fun, COLCOMP_ALWAYS

; Now set up the source (pattern) bitmap (ie the character)
; These values will be the same throughout the operation.
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; Set up the bitmap dimensions from the values in pAvioInfo
; Note that format is now padded, so the width must be whole bytes.
        movzx   eax, byte ptr [edi].bCellWidth
        dec     eax
        or      eax, 7  ; force byte width
        memregwrite     pi_map_width_B, ax

        movzx   eax, byte ptr [edi].bCellHeight
        dec     eax
        memregwrite     pi_map_height_B, ax

; set format to MOTOROLA - the pixel maps are tweaked when caching
; them in VRAM so that this will be the correct setting
        memregwrite     pi_map_format_B, ONE_BPP+MOTOROLA

; Note that after each character these will return to 0
        memregwrite     patt_map, 0

; Now loop through all the clip rectangles
        ; only use cx because we do a SWAP ecx later
        mov     cx, AIxfer.cClipRects

; Get offset to first clip rectangle and use it to initialise our
; current clip rectangle pointer
        mov     eax, AIxfer.pFirstClipRect
        mov     AIxfer.pCurrentClipRect, eax


nextclip:     ;;;; OUTER LOOP - For Each Clip Rectangle....


        swap    ecx

; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect

; The offsets
        mov     dx, [ebx].clip_y0
        mov     _SPad.clipy0, dx
        swap    edx
        mov      dx, [ebx].clip_x0
        mov     _SPad.clipx0, dx

; The height
        mov     ax, [ebx].clip_y1
        mov     _SPad.clipy1, ax
        sub     ax, [ebx].clip_y0
        swap    eax

; The width
        mov     ax, [ebx].clip_x1
        mov     _SPad.clipx1, ax
        sub     ax, [ebx].clip_x0

; Wait on the hardware before going any further
        waitshort

; we want the mask map
        memregwrite     pi_map_index_M, SEL_MASK_MAP

; Set the offsets and dimensions of the mask map
        memregwrite     mask_org, edx
        mov             mask_org_store, edx
        memregwrite     pi_map_size_M, eax

; Now set up the start position
; First the y
        mov     al, AIxfer.bRow
        mul     [edi].bCellHeight                                       ;**
        add     ax, [edi].sYoffset                                      ;**
        swap    eax

; Then the x
        mov     al, AIxfer.bColumn
        mul     [edi].bCellWidth                                        ;**
        add     ax, [edi].sXoffset                                      ;**

; Now save them
        mov     dword ptr AIxfer.sXPosition, eax

; Hang on to the start x position
        mov     AIxfer.sRowPosition, ax

; Get the start of the block in the character buffer

        mov     ebx, AIxfer.pLVBChars                                   ;**

; all references to pixel maps in this loop are for the pattern map
; pixel map B
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; Now lets GO!
        mov     cl, AIxfer.bDown

nextrow:
        mov     ch, AIxfer.bAcross

; Is the top of the next row below the bottom of the current clip
; rectangle?
        mov     ax, AIxfer.sYPosition
        cmp     ax, _SPad.clipy1
        jg      lastrow

; Is the bottom of the next row above the top of the current clip
; rectangle?
        add     al, [edi].bCellHeight                                   ;**
        adc     ah, 0
        cmp     ax, _SPad.clipy0
        jl      newrow


nextchar:      ;;;; INNER LOOP - For Each Character in the String.....


; Is the left edge of this character to the right of the current clip
; rectangle?
        mov     ax, AIxfer.sXPosition
        cmp     ax, _SPad.clipx1
        jg      newrow

; Is the right edge of this character to the left of the current clip
; rectangle?
        add     al, [edi].bCellWidth                                    ;**
        adc     ah, 0
        cmp     ax, _SPad.clipx0
        jl      newchar

; Save the loop counters
        push    ecx

; Get the next character and attribute byte
        mov     cx, [ebx]                                               ;**

; Is the foreground colour the same as it was last time?
        movzx   eax, ch                                                 ;**
        and     al, 0Fh
        cmp     al, AIxfer.bFGIndex
        jz      short samefg                                            ;**

; Foreground colour has changed so set the new one in hardware
        mov     AIxfer.bFGIndex, al

; Get the actual colour index to use and write it out
; The lookup table is dwords so eax*4
        shl     eax,2                           ; table is dwords so * 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        waitshort
        memregwrite     fg_colour, ax

samefg:
; Is the background colour the same as it was last time?
        movzx   eax, ch                                                 ;**
        and     al, 0F0h
        cmp     al, AIxfer.bBGIndex
        jz      short samebg                                            ;**

; Background colour has changed so set the new one in hardware
        mov     AIxfer.bBGIndex, al

; Get the actual colour index to use
; The lookup table is dwords so eax/4 (eax was 16* the index)
        shr     eax, 2                          ; divide by 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        waitshort
        memregwrite     bg_colour, ax

samebg:
; Get an offset from a codepoint (in cl)

; first save our pointer to the LVB
        push    ebx                                                     ;**

;/*********************************************************************/
;/* New code                                                          */
;/* NOTE don't need cp vector now, as we only cache 256 chars         */
;/*********************************************************************/
;

        movzx   ebx, cl   ; get codepoint

        ; now get the address of the glyph definition
        mov     eax, [edi].pfciTable                                    ;**

        ; Now get the address of the glyph definition
get_g_address:
        mov     eax, [eax].fci_aulCachedCharOffset[ebx*4]              ;**

ifdef FIREWALLS
        ; If this offset is zero, its all gone horribly       -
        ; all chars should have been cached.
        or      eax, eax
        jnz     short @f                                                ;**
        int 3            ; Horrible error - chars should all be cached!
        mov     ebx, 32  ; Try again with space character !?
        jmp     get_g_address
 @@:
 endif ; FIREWALLS

IFDEF CC20
        add     eax, _pCurCacheBasePhy
ENDIF

;/*********************************************************************/
;/* End of new code - have address of glyph defn in eax as before     */
;/*********************************************************************/

; Get back access to the LVB
        pop     ebx                                                     ;**

; Now work out if we can do more than one character here
; dx  will be the character we are repeating (including attributes)
        mov     edx, ecx
        pop     ecx

; Save the base address on the stack for the blt later
        push    eax

; ax will be the repeat count
        mov     eax, 1

anotherchar:
; Next cell in the LVB
        add     ebx, 2                                                  ;**

; Do we want to do any more characters anyway
        dec     ch
        jz      short nomore                                            ;**

; Is it the same as the character we've done the set up for
        cmp     dx, [ebx]                                               ;**
        jnz     short nomore                                            ;**

; Yes it is so increase our count and loop back
        inc     eax
        jmp     short anotherchar

nomore:

; Now wait for the hardware
        waitshort

; Note now cached chars are not in compact format, we cannot do all
; the characters in one blt, instead have a tight loop here.

        mov     chcount, eax

; Set up base address for character
        pop     eax
        memregwrite     pi_map_base_ptr_B, eax

; Reset the operating dimension width & hegiht
        xor     eax,eax
        mov     al, [edi].bCellHeight
        dec     al
        memregwrite     dim2, ax

        mov     al, [edi].bCellWidth                                    ;**
        dec     al
        memregwrite     dim1, ax
        inc     eax     ; Note eax contains width

; Set up the coords in edx
        mov     dx, AIxfer.sYPosition
        swap    edx
        mov     dx, AIxfer.sXPosition
        push    ecx
        mov     ecx, mask_org_store


do_next_blt_2:
; Set the position in the destination
        waitshort
        memregwrite     dest_map, edx
        memregwrite     mask_org, ecx

; Now, a bacon, lettuce & tomato please.
        memregwrite     pixel_op, AVIO_charblt

; More chars?
        add     dx, ax  ; get next position
        dec     chcount
        jnz     do_next_blt_2

; Save final x coord
        mov     AIxfer.sXPosition, dx
        pop     ecx

; Are there any more characters?
        cmp     ch, 0
        jnz     nextchar   ;;;; END INNER LOOP - For Each Char.....

; A new row
newrow:
        dec     cl
        jz      short lastrow                                           ;**

; more rows so adjust y coordinate and retrieve x coordinate for
; start of line
        xor     eax,eax
        mov     al, [edi].bCellHeight                                   ;**
        add     ax, AIxfer.sYPosition
        mov     AIxfer.sYPosition, ax
        mov     ax, AIxfer.sRowPosition
        mov     AIxfer.sXPosition, ax

; allow for any characters which we might have missed by adding
; an 2*cl to our pointer to the LVB
        xor     eax, eax                                                ;**
        mov     al, ch
        shl     ax, 1
        add     ebx, eax                                                ;**

; now move to the position in the LVB corresponding to the start of
; the next row..
; adding the .bufwidth takes us to the end of the next line then
; subtracting .across takes us back to the start of the next line
        sub     edx, edx                                                ;**
        mov     dl, AIxfer.bBufferWidth
        add     ebx, edx                                                ;**
        add     ebx, edx                                                ;**
        mov     dl, AIxfer.bAcross
        sub     ebx, edx                                                ;**
        sub     ebx, edx                                                ;**
        jmp     nextrow

lastrow:
; see if there is a new clip rectangle
        swap    ecx
        dec     cx
        jz      short lastclip                                          ;**
        mov     eax, AIxfer.pCurrentClipRect                            ;**
        add     eax, len_clip_rect                                      ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**

        jmp     nextclip     ;;;; END OUTER LOOP - For Each Clip Rect.....

newchar:
; we get to here when the characters are still to the left of the
; current clip rectangle so we haven't started printing them yet
        xor     eax, eax
        mov     al, [edi].bCellWidth                                    ;**
        add     AIxfer.sXPosition, ax

        add     ebx, 2                                                  ;**

; are there any more characters?
        dec     ch
        jnz     nextchar
        jmp     newrow

lastclip:
pmcgaexit:
; tidy up and go home
        popxga

cEnd

ELSE ; _8514

;***********************************************************************
;
; Function: CGATextBlock - 8514 Version
;
; Called by: eddv*.c modules (charrect, charstr, scrollrect)
;
; This code draws a block of CGA text into all the current clip
; rectangles.  It is arranged like this..
;       FOR each clip rectangle
;               FOR each character
;                       draw character into clip rectangle
;  ..so that we can do some elimination of characters because we know
; that the block will always be printed from top left to bottom right.
;
; This code is 386 only.
;
;***********************************************************************
; AK new version
; assumes all chars are cached in VRAM (or wherever).
; This is all the base font - no changes of font occur
;***********************************************************************

        align   4
cProc CGATextBlock,<PUBLIC>,<edi,esi,ebx>
        parmD   pFontDetails
        parmD   pAvioInfo
        localD  chcount
        localD  mask_org_store
        localW  PlaneOffset             ;75296
        ifdef   BPP24
        localD  pFocafnt
        localW  usPels
        localW  usHeight
        localW  RightClip
        localW  LeftClip
        localW  TopClip
        localW  BottomClip
        localW  x_src
        localW  y_src
        localW  TimeAround
        localW  x_inc
        localW  fGrey
        localW  CodePt
        endif

cBegin

;********************************************************************
; Are there any characters to print?
;********************************************************************
        cmp     AIxfer.bAcross, 0
        je      short no_chars
        cmp     AIxfer.bDown, 0
        jne     short some_chars

no_chars:
;********************************************************************
; Nothing here for us to do so quit
;********************************************************************
        jmp     pmcgaexit

some_chars:

;********************************************************************
; Something to do so do some set-up
; Get the base of the memory mapped registers and the codepage table
;********************************************************************
        mov     edi, pAvioInfo

;********************************************************************
; Invalidate the previous colour store (nb. writes to both fg and bg)
;********************************************************************
        mov     ax, 0FFFFh
        mov     word ptr AIxfer.bFGIndex, ax
        .erre   bBGIndex eq (bFGIndex + 1)

;********************************************************************
; Do some set up here which only needs to be done once
; AVIO CGA text WILL overpaint
;********************************************************************
        WaitQIdle
        WaitQ   5
        outwQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_S)
        outwQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_S)
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)
        mov     ebx,pFontDetails
        ifdef   BPP24
        mov     eax,[ebx].pFocaFont
        mov     pFocafnt,eax
        endif
        mov     cx, word ptr [ebx].usCachedFontIndex
        mov     eax,1
        shl     eax,cl
        ifndef  S3
        rol     al,1                            ; Read only one cache
        endif
        outwQ   READ_ENABLE,ax                  ;  located on a bit plane.
        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES   ; Expand to all planes.

;********************************************************************
; Now loop through all the clip rectangles
;********************************************************************
        ; only use cx because we do a SWAP ecx later
        mov     cx, AIxfer.cClipRects

;********************************************************************
; Get offset to first clip rectangle and use it to initialise our
; current clip rectangle pointer
;********************************************************************
        mov     eax, AIxfer.pFirstClipRect
        mov     AIxfer.pCurrentClipRect, eax

              ;;*****************************************************
nextclip:     ;; OUTER LOOP - For Each Clip Rectangle....
              ;;*****************************************************

        swap    ecx

;********************************************************************
; Get offset to current clip rectangle
;********************************************************************
        mov     ebx, AIxfer.pCurrentClipRect

;********************************************************************
; The offsets
;********************************************************************
ifdef   BPP24
        mov     ax, [ebx].clip_x1
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
        add     ax,2
@@:
        mov     RightClip,ax
        mov     ax, [ebx].clip_x0
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        mov     LeftClip,ax


        setclip LeftClip,[ebx].clip_y0,RightClip,[ebx].clip_y1

        mov     ax, [ebx].clip_x0
        mov     LeftClip,ax
        mov     ax, [ebx].clip_x1
        mov     RightClip,ax
        mov     ax,[ebx].clip_y0
        mov     TopClip,ax
        mov     ax,[ebx].clip_y1
        mov     BottomClip,ax

else
        setclip [ebx].clip_x0,[ebx].clip_y0,[ebx].clip_x1,[ebx].clip_y1
endif


        mov     dx, [ebx].clip_y0
        mov     _SPad.clipy0, dx
;;        swap    edx
        mov     dx, [ebx].clip_x0
        mov     _SPad.clipx0, dx

;********************************************************************
; The height
;********************************************************************
        mov     ax, [ebx].clip_y1
        mov     _SPad.clipy1, ax
;;        sub     ax, [ebx].clip_y0
;;        swap    eax

;********************************************************************
; The width
;********************************************************************
        mov     ax, [ebx].clip_x1
        mov     _SPad.clipx1, ax
;;        sub     ax, [ebx].clip_x0

;********************************************************************
; Now set up the start position
; First the y and x
;********************************************************************
        mov     al, AIxfer.bRow
        mul     [edi].bCellHeight                                       ;**
        add     ax, [edi].sYoffset                                      ;**
        swap    eax

        mov     al, AIxfer.bColumn
        mul     [edi].bCellWidth                                        ;**
        add     ax, [edi].sXoffset                                      ;**

;********************************************************************
; Now save them
;********************************************************************
        mov     dword ptr AIxfer.sXPosition, eax

;********************************************************************
; Hang on to the start x position
;********************************************************************
        mov     AIxfer.sRowPosition, ax

;********************************************************************
; Get the start of the block in the character buffer
;********************************************************************

        mov     ebx, AIxfer.pLVBChars                                   ;**

;********************************************************************
; Now lets GO!
;********************************************************************
        mov     cl, AIxfer.bDown

nextrow:
        mov     ch, AIxfer.bAcross

;********************************************************************
; Is the top of the next row below the bottom of the current clip
; rectangle?
;********************************************************************
        mov     ax, AIxfer.sYPosition
        cmp     ax, _SPad.clipy1
        jg      lastrow

;********************************************************************
; Is the bottom of the next row above the top of the current clip
; rectangle?
;********************************************************************
        add     al, [edi].bCellHeight                                   ;**
        adc     ah, 0
        cmp     ax, _SPad.clipy0
        jl      newrow

               ;;****************************************************
nextchar:      ;; INNER LOOP - For Each Character in the String.....
               ;;****************************************************

;********************************************************************
; Is the left edge of this character to the right of the current clip
; rectangle?
;********************************************************************
        mov     ax, AIxfer.sXPosition
        cmp     ax, _SPad.clipx1
        jg      newrow

;********************************************************************
; Is the right edge of this character to the left of the current clip
; rectangle?
;********************************************************************
        add     al, [edi].bCellWidth                                    ;**
        adc     ah, 0
        cmp     ax, _SPad.clipx0
        jl      newchar

;********************************************************************
; Save the loop counters
;********************************************************************
        push    ecx

;********************************************************************
; Get the next character and attribute byte
;********************************************************************
        mov     cx, [ebx]                                               ;**

;********************************************************************
; Is the foreground colour the same as it was last time?
;********************************************************************
        movzx   eax, ch                                                 ;**
        and     al, 0Fh
        cmp     al, AIxfer.bFGIndex
        jz      short samefg                                            ;**

;********************************************************************
; Foreground colour has changed so set the new one in hardware
;********************************************************************
        mov     AIxfer.bFGIndex, al

;********************************************************************
; Get the actual colour index to use and write it out
; The lookup table is dwords so eax*4
;********************************************************************
        shl     eax,2                           ; table is dwords so * 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     edx,COLOR_1
        out     dx,ax

samefg:
;********************************************************************
; Is the background colour the same as it was last time?
;********************************************************************
        movzx   eax, ch                                                 ;**
        and     al, 0F0h
        cmp     al, AIxfer.bBGIndex
        jz      short samebg                                            ;**

;********************************************************************
; Background colour has changed so set the new one in hardware
;********************************************************************
        mov     AIxfer.bBGIndex, al

;********************************************************************
; Get the actual colour index to use
; The lookup table is dwords so eax/4 (eax was 16* the index)
;********************************************************************
        shr     eax, 2                          ; divide by 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     edx, COLOR_0
        out     dx,ax

samebg:
;********************************************************************
; Get an offset from a codepoint (in cl)
;
; first save our pointer to the LVB
;********************************************************************
        push    ebx                                                     ;**

;/*********************************************************************/
;/* New code                                                          */
;/* NOTE don't need cp vector now, as we only cache 256 chars         */
;/*********************************************************************/
;
        movzx   ebx, cl   ; get codepoint
        ifdef   BPP24
        mov     CodePt, bx   ; get codepoint
        endif

        ; now get the address of the glyph definition
        mov     eax, [edi].pfciTable                                    ;**

        ; Now get the address of the glyph definition
get_g_address:

        mov     dx, [eax].fci_ausFontPlaneOffset[ebx*2]                ;75206
        mov     PlaneOffset,dx                                         ;75206

        mov     eax, [eax].fci_aulCachedCharOffset[ebx*4]              ;**

ifdef FIREWALLS
        ; If this offset is zero, its all gone horribly       -
        ; all chars should have been cached.
        or      eax, eax
        jnz     short @f                                                ;**
        int 3            ; Horrible error - chars should all be cached!
        mov     ebx, 32  ; Try again with space character !?
        jmp     get_g_address
 @@:
 endif ; FIREWALLS


;/*********************************************************************/
;/* End of new code - have address of glyph defn in eax as before     */
;/*********************************************************************/

; Get back access to the LVB
        pop     ebx                                                     ;**

;********************************************************************
; Now work out if we can do more than one character here
; dx  will be the character we are repeating (including attributes)
;********************************************************************
        mov     edx, ecx
        pop     ecx

;********************************************************************
; Save the base address on the stack for the blt later
;********************************************************************
        push    eax

;********************************************************************
; ax will be the repeat count
;********************************************************************
        mov     eax, 1

anotherchar:
; Next cell in the LVB
        add     ebx, 2                                                  ;**

; Do we want to do any more characters anyway
        dec     ch
        jz      short nomore                                            ;**

; Is it the same as the character we've done the set up for
        cmp     dx, [ebx]                                               ;**
        jnz     short nomore                                            ;**

; Yes it is so increase our count and loop back
        inc     eax
        jmp     short anotherchar

nomore:

;********************************************************************
; Note now cached chars are not in compact format, we cannot do all
; the characters in one blt, instead have a tight loop here.
;********************************************************************

        mov     chcount, eax

;********************************************************************
; Set up base address for character
;********************************************************************

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      not_24bpp

        ; check for non greys and let them pass
        mov     fGrey,1
        movzx   eax,AIxfer.bFGIndex
        shl     eax,2                           ; table is dwords so * 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     _Shadow8514Regs.Color_1,eax
        movzx   eax,AIxfer.bBGIndex
        shr     eax,2                           ; was * 16 so div by four
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     _Shadow8514Regs.Color_0,eax
        rol     eax,8                           ; XXBBGGRR -> BBGGRRXX
        mov     al,ah                           ; BBGGRRRR
        ror     eax,8                           ; RRBBGGRR
        xor     al,ah                           ; GG == RR?
        jnz     not_grey                        ; no, not gray
        shr     eax,16                          ; 0000RRBB
        xor     al,ah                           ; RR == BB?
        jnz     not_grey
        mov     eax,_Shadow8514Regs.Color_1
        rol     eax,8                           ; XXBBGGRR -> BBGGRRXX
        mov     al,ah                           ; BBGGRRRR
        ror     eax,8                           ; RRBBGGRR
        xor     al,ah                           ; GG == RR?
        jnz     not_grey                        ; no, not gray
        shr     eax,16                          ; 0000RRBB
        xor     al,ah                           ; RR == BB?
        jnz     not_grey                        ; no, not grey
        cmp     _CouldntCache,0                 ; were we able to cache?
        jnz     not_grey                        ; no, blt the text
        jmp     not_24bpp                       ; yes, its cached and grey
not_grey:
        pop     eax
        push    ecx                     ; Save it
        mov     fGrey,0
        mov     x_inc,0
        mov     si, AIxfer.sXPosition

        swap    esi                     ; get in x-y format
        mov     si, AIxfer.sYPosition
        swap    esi                     ; return to y-x format

do_next_blt_24:
        mov     edi, pAvioInfo

        mov     x_src,0                 ; assume no clipping
        mov     y_src,0
        mov     TimeAround,0
        mov     eax,esi
        movzx   edx,[edi].bCellWidth    ; ax = x dest  dx = blt width
        mov     usPels,dx               ; assume full char width
        cmp     ax,LeftClip             ; any clipping on left?
        jge     LeftOK                  ; no, check right edge
        add     ax,dx                   ; ax = right edge of blt
        sub     ax,LeftClip             ; are we totally clipped out?
        jle     done_24_char            ; yes, don't bother
        mov     usPels,ax               ; new blt width
        mov     dx,ax                   ; save for later
        mov     ax,LeftClip
        sub     ax,si
        mov     x_src,ax
        add     si,ax                   ; new x dest
        mov     ax,si                   ; check right edge
LeftOK:
        cmp     ax,RightClip            ; are we totally clipped out?
        jg      done_24_char            ; yes
        add     ax,dx                   ; dx has blt width
        sub     ax,RightClip
        jle     RightOK
        dec     ax
        sub     usPels,ax
        jz      done_24_char
RightOK:
        shr     eax,16                  ; ax = y dest
        cmp     ax,BottomClip           ; are we totaly clipped out?
        jg      done_24_char            ; yes
        movzx   edx,[edi].bCellHeight
        sub     ax,TopClip
        jge     TopOK
        neg     ax
        sub     dx,ax                   ; new height
        jle     done_24_char
        mov     y_src,ax
        rol     esi,16
        add     si,ax
        rol     esi,16
TopOK:
        mov     eax,esi
        shr     eax,16
        add     ax,dx                   ; ax = bottom of blt
        sub     ax,BottomClip
        jle     BottomOK
        dec     ax
        sub     dx,ax
        jle     done_24_char
BottomOK:
        mov     usHeight,dx

        movzx   eax, [edi].bCellWidth
CGA24TopLoop:
        sub     ax,8
        jge     @f
        xor     ax,ax                   ; last time around
@@:
        push    ax

        mov     ax,x_src
        cmp     ax,8
        jge     CGASkipBlt

        push    ax                      ; bits into first byte

        push    ONE_BPP                 ; format

        movzx   edx,usHeight
        dec     edx                     ; make zero-based
        push    edx                     ; height

        mov     eax,7                   ; do one byte column
        push    eax                     ; bmap width

        movzx   edx,usPels
        mov     ax,dx
        add     ax,x_src
        sub     ax,8
        jle     @f
        sub     dx,ax
@@:
        sub     usPels,dx               ; get usPels ready for next time around
        dec     edx                     ; Make zero-based
        push    edx                     ; blt width


        swap    esi                     ; get in x-y format
        push    esi                     ; vram dest

        ; now get the address of the char definition
        push    ebx
        movzx   ebx, CodePt             ; get codepoint
        mov     eax, [edi].pfciTable
ifdef FULL_ADDRESS
        mov     eax, [eax].fci_apCharDef[ebx*4]
else ; ndef FULL_ADDRESS
        movzx   eax, word ptr [eax].fci_apCharDef[ebx*2]
        add     eax, pFocafnt
endif ; ndef FULL_ADDRESS
        mov     ebx, [eax]
        movzx   eax,[edi].bCellHeight
        mul     TimeAround
        add     eax,ebx
        add     eax, pFocafnt

        add     ax,y_src

        pop     ebx

        push    eax                     ; memory source
        call    _Copy24MonoToVRAM
        add     esp,26

        swap    esi                     ; return to y-x format

CGASkipBlt:

        inc     TimeAround
        mov     ax,x_src
        cmp     ax,8                    ; did we do anything?
        jl      CGASubXSrc              ; yes
        sub     ax,8                    ; no, update x_src and try again
        mov     x_src,ax
        jmp     @f
CGASubXSrc:
        sub     si,x_src                ; subtract what we added for x_src
        mov     x_src,0                 ; we are through with the x offset
        add     si,8                    ; get ready for next byte
@@:
        pop     ax
        or      ax,ax                   ; any pels left?
        jnz     CGA24TopLoop            ; yes, go back around
        movzx   ecx,TimeAround          ; no, clean up and go on
@@:
        sub     si,8                    ; put si back to where we found it
        loop    @b

done_24_char:

        sub     si,x_src                ; subtract what we added for x_src
        rol     esi,16                  ; go to x-y format
        sub     si,y_src                ; subtract what we added for y_src
        rol     esi,16                  ; return to y-x format

        movzx   ax,byte ptr [edi].bCellWidth
        mov     di,ax
        mov     cx,ax                   ; Note ecx contains width

        jmp     done_cga_char
not_24bpp:
endif

        WaitQIdle

        WaitQ   4
        pop     eax
        push    ecx                     ; Save it

        calc8514xy      eax
        mov     ecx,edx
        outwQ   Y0,ax
        mov     eax,ecx
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     dx,3
        mul     dx
@@:
endif
        outwQ   X0,ax

        pop     ecx                     ; Restore it

;********************************************************************
; Reset the operating dimension width & height
;********************************************************************
        xor     eax,eax
        mov     al, [edi].bCellHeight
        dec     al
        outwQ   LY,ax

        mov     al, [edi].bCellWidth                                    ;**
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        ; the cell width is already one based.
        mov     x_inc,0
        movzx   di,al
        mov     dx,3
        mul     dx
@@:
endif
        dec     al
        outwQ   LX,ax

        inc     eax
        push    ecx
        mov     ecx,eax ; Note ecx contains width

;********************************************************************
; Set up the coords in edx
;********************************************************************
        mov     si, AIxfer.sYPosition
        swap    esi
        mov     si, AIxfer.sXPosition
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     ax,si
        mov     dx,3
        mul     dx
        mov     si,ax
@@:
endif


do_next_blt_2:
;********************************************************************
; Set the position in the destination
;********************************************************************
        WaitQ   2
        outwQ   X1,si
        swap    esi
        outwQ   Y1,si
        swap    esi

        ; start 75206
        WaitQ   2
        mov     dx, PlaneOffset
        cmp     dx,-1                           ; are we in 16 bit color?
        jz      @f                              ; no, the read plane is set
        push    ebx                             ; yes, we might have to go to 
        push    ecx                             ;  plane Index+8 or back to Index
        and     dx,1                            ; just in case
        shl     dx,3
        mov     ebx,pFontDetails
        mov     cx, word ptr [ebx].usCachedFontIndex
        add     cx,dx
        mov     eax,1
        shl     eax,cl
        outwQ   READ_ENABLE,ax                  ; located on a bit plane.
        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES   ; Expand to all planes.
        pop     ecx
        pop     ebx
@@:
        ; end 75206

;********************************************************************
; Now, a bacon, lettuce & tomato please.
;********************************************************************
        WaitQ   1
        outwQ   CMD_FLAGS,CMD_DRAWTEXT

ifdef BPP24
done_cga_char:
endif

;********************************************************************
; More chars?
;********************************************************************
        add     si, cx  ; get next position
        ifdef   BPP24
        add     x_inc,di
        endif

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        test    fGrey,1
        jnz     @f

        dec     chcount
        jnz     do_next_blt_24
        jmp     dec_done
@@:
        dec     chcount
        jnz     do_next_blt_2
dec_done:
else
        dec     chcount
        jnz     do_next_blt_2
endif

;********************************************************************
; Save final x coord
;********************************************************************
        ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     si,AIxfer.sXPosition
        add     si,x_inc
        mov     edi,pAvioInfo
@@:
        endif

        mov     AIxfer.sXPosition, si
        pop     ecx

;********************************************************************
; Are there any more characters?
;********************************************************************
        ; @DMS put here in case we change colors
        WaitQ   2
        cmp     ch, 0
        jnz     nextchar   ;;;; END INNER LOOP - For Each Char.....

;********************************************************************
; A new row
;********************************************************************
newrow:
        dec     cl
        jz      short lastrow                                           ;**

;********************************************************************
; more rows so adjust y coordinate and retrieve x coordinate for
; start of line
;********************************************************************
        xor     eax,eax
        mov     al, [edi].bCellHeight                                   ;**
        add     ax, AIxfer.sYPosition
        mov     AIxfer.sYPosition, ax
        mov     ax, AIxfer.sRowPosition
        mov     AIxfer.sXPosition, ax

;********************************************************************
; allow for any characters which we might have missed by adding
; an 2*cl to our pointer to the LVB
;********************************************************************
        xor     eax, eax                                                ;**
        mov     al, ch
        shl     ax, 1
        add     ebx, eax                                                ;**

;********************************************************************
; now move to the position in the LVB corresponding to the start of
; the next row..
; adding the .bufwidth takes us to the end of the next line then
; subtracting .across takes us back to the start of the next line
;********************************************************************
        sub     edx, edx                                                ;**
        mov     dl, AIxfer.bBufferWidth
        add     ebx, edx                                                ;**
        add     ebx, edx                                                ;**
        mov     dl, AIxfer.bAcross
        sub     ebx, edx                                                ;**
        sub     ebx, edx                                                ;**
        jmp     nextrow

lastrow:
;********************************************************************
; see if there is a new clip rectangle
;********************************************************************
        swap    ecx
        dec     cx
        jz      short lastclip                                          ;**
        mov     eax, AIxfer.pCurrentClipRect                            ;**
        add     eax, len_clip_rect                                      ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**

                            ;;**************************************
        jmp     nextclip    ;; END OUTER LOOP - For Each Clip Rect.....
                            ;;**************************************

newchar:
;********************************************************************
; we get to here when the characters are still to the left of the
; current clip rectangle so we haven't started printing them yet
;********************************************************************
        xor     eax, eax
        mov     al, [edi].bCellWidth                                    ;**
        add     AIxfer.sXPosition, ax

        add     ebx, 2                                                  ;**

;********************************************************************
; are there any more characters?
;********************************************************************
        dec     ch
        jnz     nextchar
        jmp     newrow

lastclip:
pmcgaexit:
;********************************************************************
; tidy up and go home
;********************************************************************
        WaitQ   1
        outwQ   READ_ENABLE,READ_ALL_PLANES
        ifndef  S3
        setclip 0,0,SCR_8514_WIDTH-1,SCR_8514_HEIGHT-1
        else
        setclip 0,0,SCR_S3_WIDTH-1,SCR_S3_HEIGHT-1
        endif

cEnd

ENDIF ; _8514

IFNDEF _8514

;***********************************************************************
;
; Function: MFITextBlock - XGA Version
;
; Called by: eddv*.c modules (charrect, charstr, scrollrect)
;
; This code draws a block of MFI text into all the current clip
; rectangles.  It is arranged like this..
;       FOR each clip rectangle
;               FOR each character
;                       draw character into clip rectangle
;  ..so that we can do some elimination of characters because we know
; that the block will always be printed from top left to bottom right.
;
; This code is 386 only.
;***********************************************************************

        align   4
cProc MFITextBlock <PUBLIC>,<edi,esi,ebx>
        parmD   pFontDetails
        parmD   pAvioInfo
        localD  ediStore
        localD  baseStore
        localD  eaxStore
        localD  mask_org_store
        localW  chcount

cBegin
        pushxga

; Are there any characters to print?
        cmp     AIxfer.bAcross, 0
        je      short no_chars1                                         ;**
        cmp     AIxfer.bDown, 0
        jne     short some_chars1                                       ;**

no_chars1:
; Nothing here for us to do so quit
        jmp     pmmfiexit

some_chars1:

; Call off to cache the chars
;       push    pFontDetails
;       push    pAvioInfo
;       call    eddh_update_cache_charrect_4
;       or      ax, ax
;       jnz     not_invalidated_4
;
; The cache was full and has been invalidated: try again
;
;       push    pFontDetails
;       call    eddt_LocateCachedFont
;
;       push    pFontDetails
;       push    pAvioInfo
;       call    eddh_update_cache_charrect_4
;       or      ax, ax
;       jnz     not_invalidated_4
; BIG TROUBLE !!!!
;       int 3

not_invalidated_4:

; Something to do so get do some set-up
; Get the font header and the base of the memory mapped registers
        ifndef  _8514
        movxga  _pRealXGARegs
        else
        movxga  _pReal8514Regs
        endif
        mov     edi, pAvioInfo  ; /* for font zero = base   */          ;**
        mov     eax, [edi].pfciTable                                    ;**
        mov     baseStore, eax
        mov     ediStore, eax

; Invalidate the previous colour store (nb. writes to both fg and bg)
        mov     ax, 0FFFFh
        mov     word ptr AIxfer.bFGIndex, ax                            ;**
        .ERRE   bBGIndex eq (bFGIndex + 1)

;/*********************************************************************/
;/* AK: no locking in new scheme. Cached chars already locked in.     */
;/*********************************************************************/

; Set up the destination bitmap (will be the screen)
        waitshort

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest                                    ;**
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; physical address
        mov     eax, [ebx+phys_addr]                                    ;**
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     ax, [ebx+hw_height]                                     ;**
        swap    eax
        mov     ax, [ebx+hw_width]                                      ;**
        memregwrite     pi_map_size_A, eax

; format
        mov     ax, [ebx+hw_format]                                     ;**
        memregwrite     pi_map_format_A, al

; Do some set up here which only needs to be done once
; Foreground mix will be overpaint
        memregwrite     fg_mix, 03h
        memregwrite     colour_comp_fun, COLCOMP_ALWAYS

; Now set up the source (pattern) bitmap (ie the character)
; These values will be the same throughout the operation.
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; Set up the bitmap dimensions for a character cell
; Note that format is now padded, so the widht must be whole bytes.
        sub     ax, ax
        mov     al, [edi].bCellWidth                                    ;**
        dec     al
        or      ax, 7   ;force byte width
        memregwrite     pi_map_width_B, ax

        mov     al, [edi].bCellHeight                                   ;**
        dec     ax
        memregwrite     pi_map_height_B, ax
        memregwrite     pi_map_format_B, ONE_BPP+MOTOROLA

; Note that after each character these will return to 0
        memregwrite     patt_map, 0

;/*********************************************************************/
;/* No locking now                                                    */
;/*********************************************************************/
; The base font is already locked down and in VRAM if possible

; Now loop through all the clip rectangles
        mov     cx, AIxfer.cClipRects

; Get offset to first clip rectangle and us it to initialise our current
; clip rectangle pointer
        mov     eax, AIxfer.pFirstClipRect                              ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**

;/*********************************************************************/
;/* Not sure about this. All four fonts now equally available...      */
;/*********************************************************************/
; The current font starts as the default font
        mov     _SPad.fontnum, 0h

nextclip1:
        swap    ecx

; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect                            ;**

; The offsets
        mov     dx, [ebx].clip_y0                                       ;**
        mov     _SPad.clipy0, dx
        swap    edx
        mov     dx, [ebx].clip_x0
        mov     _SPad.clipx0, dx

; The height
        mov     ax, [ebx].clip_y1                                       ;**
        mov     _SPad.clipy1, ax
        sub     ax, [ebx].clip_y0                                       ;**
        swap    eax

; The width
        mov     ax, [ebx].clip_x1                                       ;**
        mov     _SPad.clipx1, ax
        sub     ax, [ebx].clip_x0                                       ;**

; Wait on the hardware before going any further
        waitshort

; we want the mask map
        memregwrite     pi_map_index_M, SEL_MASK_MAP

; Set the offsets and dimensions of the mask map
        mov             mask_org_store, edx
        memregwrite     mask_org, edx
        memregwrite     pi_map_size_M, eax

; Now set up the start position
; First the y
        mov     al, AIxfer.bRow
        mul     [edi].bCellHeight                                       ;**
        add     ax, [edi].sYoffset                                      ;**
        swap    eax

; Then the x
        mov     al, AIxfer.bColumn
        mul     [edi].bCellWidth                                        ;**
        add     ax, [edi].sXoffset                                      ;**

; Now save them
        mov     dword ptr AIxfer.sXPosition, eax

; Hang on to the start x position
        mov     AIxfer.sRowPosition, ax


; Get the start of the block in the character buffer
        mov     ebx, AIxfer.pLVBChars                                   ;**

; all references to pixel maps in this loop are for the pattern map
; pixel map B
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; Now lets GO!
        sub     cx, cx
        mov     cl, AIxfer.bDown

nextrow1:
        mov     ch, AIxfer.bAcross

; Is the top of the next row below the bottom of the current clip
; rectangle?
        mov     ax, AIxfer.sYPosition
        cmp     ax, _SPad.clipy1
        jg      lastrow1

; Is the bottom of the next row above the top of the current clip
; rectangle?
        add     al, [edi].bCellHeight                                   ;**
        adc     ah, 0
        cmp     ax, _SPad.clipy0
        jl      newrow1

nextchar1:
; Is the left edge of this character to the right of the current clip
; rectangle?
        mov     ax, AIxfer.sXPosition
        cmp     ax, _SPad.clipx1
        jg      newrow1

; Is the right edge of this character to the left of the current clip
; rectangle?
        add     al, [edi].bCellWidth                                    ;**
        adc     ah, 0
        cmp     ax, _SPad.clipx0
        jl      newchar1

; save the loop counters
        push    ecx

; Get the next character, attribute byte and extended attribute byte
        mov     ecx, [ebx]                                              ;**

; Is it the same font as last time?
        mov     eax, ecx
        swap    eax
        .ERRNZ  MFI_FONTBITS AND 0ffffff00h                             ;**
        and     eax, MFI_FONTBITS                                       ;**
        cmp     al, _SPad.fontnum
        jz      short samefont                                          ;**

;
; NEW CODE
;
; not same font - so get the FontCacheInfo pointer from al

; Store the number of the new font
        mov     _SPad.fontnum, al

        ; Make sure font is present (non-null entry in pfciTable)
        mov     edi, pAvioInfo                                          ;**
        mov     eax, dword ptr [edi+eax*4].pfciTable ; Get the pointer  ;**
        or      eax, eax                          ; Is it null?
        jnz     short ok_font_present                                   ;**
        mov     eax, baseStore            ; Yes - use base font

ok_font_present:
        mov     ediStore, eax            ; save pointer to cache table

samefont:
       ; Now check for inverse video
        mov     edi, ediStore            ; edi points into cache table  ;**
        test    ecx, MFI_REV_VIDEO
        jz      short normalvid                                         ;**

        ; The reverse video bit is set so swap background and foreground colours
        rol     ch, 4

normalvid:
        ; Is the foreground colour the same as it was last time?
        movzx   eax, ch                                                 ;**
        and     al, 0Fh
        cmp     al, AIxfer.bFGIndex
        jz      short samefg1                                           ;**

; Foreground colour has changed so set the new one in hardware
        mov     AIxfer.bFGIndex, al

; Get the actual colour index to use and write it out
; The lookup table is dwords so eax*4
        shl     eax,2                           ; table is dwords so * 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        waitshort
        memregwrite     fg_colour, ax

samefg1:
; Is the background colour the same as it was last time?
        movzx   eax, ch                                                 ;**
        and     al, 0F0h
        cmp     al, AIxfer.bBGIndex
        jz      short samebg1                                           ;**

; Background colour has changed so set the new one in hardware
        mov     AIxfer.bBGIndex, al

; Get the actual colour index to use
; The lookup table is dwords so eax/4 (eax was 16* the index)
        shr     eax, 2                          ; divide by 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        waitshort
        memregwrite     bg_colour, ax

samebg1:

        push    ebx             ; save ebx
        movzx   ebx, cl         ; get codepoint

        ; now get the address of the glyph definition
get_g_addr:
        mov     eax, [edi].fci_aulCachedCharOffset[ebx*4]              ;**
ifdef FIREWALLS
        ; if eax is zero, its all gone horribly wrong!
        or      eax, eax
        jnz     short @f                                                ;**
        int 3   ; horrible error - chars should all be cached!
        mov     ebx, 32  ; try again with space ?! (inf loop if this fails)
        jmp     get_g_addr
 @@:
 endif ; FIREWALLS

IFDEF CC20
        add     eax, _pCurCacheBasePhy
ENDIF
        pop     ebx             ; restore ebx
        mov     edi, pAvioInfo  ; restore pointer for Avio info         ;**

; now work out if we can repeat characters
; edx will be the character we are trying to repeat (including all
; attributes)
        mov     edx, ecx
        pop     ecx

; save the address of the character image in the stack
        push    eax

; ax will be the repeat count
        mov     ax, 1

anotherchar1:
; Next cell in the LVB
        add     ebx, 4                                                  ;**

; Do we want to do any more characters anyway
        dec     ch
        jz      short nomore1                                           ;**

; Is it the same as the character we've done the set up for
        cmp     edx, [ebx]                                              ;**
        jnz     short nomore1                                           ;**

; Yes it is so increase our count and loop back
        inc     ax
        jmp     short anotherchar1

nomore1:
; Now wait for the hardware
        waitshort

; handle opaque/transparent background
        test    edx, MFI_TRANSPARENT
        jnz     short transparent                                       ;**

        memregwrite     bg_mix, 03h
        jmp     short done_opaque                                       ;**

transparent:
        memregwrite     bg_mix, 05h

done_opaque:

; Note now cached chars are not in compact format, we cannot do all
; the characters in one blt, instead have a tight loop here.
        mov     chcount, ax

; Set up base address for character
        xchg    eax, ss:[esp]   ; Get address of character image off stack,
                                ; and save eax.
        memregwrite     pi_map_base_ptr_B, eax
        pop     eax             ; restore eax

; save the character cell for future use and also the repeat count
        push    eax
        push    edx

; Reset the operating dimension width & hegiht
        sub     ax, ax
        mov     al, [edi].bCellHeight                                   ;**
        dec     al
        memregwrite     dim2, ax

        mov     al, [edi].bCellWidth                                    ;**
        dec     al
        memregwrite     dim1, ax
        inc     ax      ; Note ax contains width

; Set up the coords in edx
        mov     dx, AIxfer.sYPosition
        swap    edx
        mov     dx, AIxfer.sXPosition
; Save ecx
        push    ecx
        mov     ecx, mask_org_store

do_next_blt_4:
; Set the position in the destination
        waitshort
        memregwrite     dest_map, edx
        memregwrite     mask_org, ecx

; Now, a bacon, lettuce & tomato please.
        memregwrite     pixel_op, AVIO_charblt

; More chars?
        add     dx, ax  ; get next position
        dec     chcount
        jnz     do_next_blt_4

; Restore ecx
        pop     ecx

; get back the character cell
        pop     edx

; /* OLD CODE */
;; now wait for the hardware
;        waitshort
;
;; handle opaque/transparent background
;        test    edx, MFI_TRANSPARENT
;        jnz     transparent
;
;        memregwrite     bg_mix, 03h
;        jmp     done_opaque
;
;transparent:
;        memregwrite     bg_mix, 05h
;
;done_opaque:
;
;; set up base address for character
;        xchg    eax, ss:[esp]   ; Get address of character image off stack,
;                                ; and save eax.
;        memregwrite     pi_map_base_ptr_B, eax
;        pop     eax             ; restore eax
;
;; save the character cell for future use and also the repeat count
;        push    ax
;        push    edx
;
;; set the position in the destination
;        mov     dx, AIxfer.sYPosition
;        swap    edx
;        mov     dx, AIxfer.sXPosition
;        memregwrite     dest_map, edx
;
;
;; Set the width dimension to do al characters
;        mul     byte ptr [edi].bCellWidth                      ;**
;        dec     ax
;        memregwrite     dim1, ax
;
;; reset the operating dimension height
;        sub     ax, ax
;        mov     al, [edi].bCellHeight                          ;**
;        dec     al
;        memregwrite     dim2, ax
;
;; Now, a bacon, lettuce & tomato please..
;        memregwrite     pixel_op, AVIO_charblt
;
;; get back the character cell
;        pop     edx
;

; Now check for overstrike and/or underscore
; edx holds the character cell
        test    edx, MFI_USCORE
        jz      short nouscore                                          ;**

; there is an underscore on the last character(s) printed
        mov     eax, dword ptr [AIxfer.sXPosition]
        swap    eax

; the underscore is a solid line two pels form the bottom of the cell
        add     al, [edi].bCellHeight                                   ;**
        adc     ah, 0
        sub     ax, 2
        swap    eax

; wait for the character blt to finish
        waitshort
        memregwrite     dest_map, eax

; refresh ax (the repeat count)
        pop     eax
        push    eax

; set the operating dimensions to underscore ax characters
        mul     [edi].bCellWidth                                        ;**
        dec     al
        memregwrite     dim1, ax

        memregwrite     dim2, 0

; do the blt
        mov     eax, AVIO_usblt
        memregwrite     pixel_op, eax

nouscore:
IFDEF OVERSTRIKE
        test    edx, MFI_OSTRIKE
        jz      noostrike

; there is an overstrike on the last character(s) printed
; an overstrike is a solid line through the midlle of the cell
        sub     ax, ax
        mov     al, [edi].bCellHeight                                   ;**
        shr     al, 1
        add     ax, AIxfer.sYPosition
        swap    eax
        mov     ax, AIxfer.sXPosition

; wait for the last blt to finish
        waitshort
        memregwrite     dest_map, eax

; refresh ax (the repeat count)
        pop     ax
        push    ax

; set the operating dimensions to do overstrike ax characters
        mul     byte ptr [edi].bCellWidth                               ;**
        dec     al
        memregwrite     dim1, ax

        memregwrite     dim2, 0

; do the blt
        mov     eax, AVIO_usblt
        memregwrite     pixel_op, eax

noostrike:
ENDIF

; And moving on to the next position..
; get the repeat count and update the x position
        pop     eax
        mul     byte ptr [edi].bCellWidth                               ;**
        add     AIxfer.sXPosition, ax

; are there any more characters
        cmp     ch, 0
        jnz     nextchar1

newrow1:
; A new row
        dec     cl
        jz      short lastrow1                                          ;**

; more rows so adjust the y coordinate and retrieve the x coordinate
; for the start of a row
        sub     ax, ax
        mov     al, [edi].bCellHeight                                   ;**
        add     ax, AIxfer.sYPosition
        mov     AIxfer.sYPosition, ax
        mov     ax, AIxfer.sRowPosition
        mov     AIxfer.sXPosition, ax

; allow for any characters which we might have missed by adding
; an 4*cl to our pointer to the LVB
        sub     eax, eax                                                ;**
        mov     al, ch
        shl     ax, 2
        add     ebx, eax                                                ;**

; now move to the position in the LVB corresponding to the start of the
; next row..
        movzx   eax, byte ptr AIxfer.bBufferWidth   ; width of the buffer
        sub     al, AIxfer.bAcross              ; minus chars we already drew
        shl     eax, 2          ; each entry in the lvb is 4 bytes
        add     ebx, eax
        jmp     nextrow1

lastrow1:
; is there a new clip rectangle
        swap    ecx
        dec     cx
        jz      short lastclip1                                         ;**
        mov     eax, AIxfer.pCurrentClipRect                            ;**
        add     eax, len_clip_rect                                      ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**
        jmp     nextclip1

newchar1:
; we get here when the characters are still to the left of the clip
; rectangle
        sub     ax, ax
        mov     al, [edi].bCellWidth                                    ;**
        add     AIxfer.sXPosition, ax

        add     ebx, 4

; are there any more characters
        dec     ch
        jnz     nextchar1
        jmp     newrow1

lastclip1:
pmmfiexit:
        popxga
cEnd

ELSE ; _8514

;**********************************************************************
;
; Function: MFITextBlock - 8514 Version
;
; Called by: eddv*.c modules (charrect, charstr, scrollrect)
;
; This code draws a block of MFI text into all the current clip
; rectangles.  It is arranged like this..
;       FOR each clip rectangle
;               FOR each character
;                       draw character into clip rectangle
;  ..so that we can do some elimination of characters because we know
; that the block will always be printed from top left to bottom right.
;
; This code is 386 only.
;**********************************************************************

        align   4
cProc MFITextBlock <PUBLIC>,<edi,esi,ebx>
        parmD   pFontDetails
        parmD   pAvioInfo
        localD  ediStore
        localD  baseStore
        localD  charinfo
        localD  chcount
        localW  PlaneOffset             ;75296
        ifdef   BPP24
        localD  pFocafnt
        localW  usPels
        localW  usHeight
        localW  RightClip
        localW  LeftClip
        localW  TopClip
        localW  BottomClip
        localW  x_src
        localW  y_src
        localW  TimeAround
        localW  x_inc
        localW  fGrey
        localW  CodePt
        endif

cBegin

;********************************************************************
; Are there any characters to print?
;********************************************************************
        cmp     AIxfer.bAcross, 0
        je      short no_chars1
        cmp     AIxfer.bDown, 0
        jne     short some_chars1

no_chars1:
;********************************************************************
; Nothing here for us to do so quit
;********************************************************************
        jmp     pmmfiexit

some_chars1:

;********************************************************************
; Something to do so do some set-up
; Get the base of the memory mapped registers and the codepage table
;********************************************************************
        mov     edi, pAvioInfo
        mov     eax, [edi].pfciTable
        mov     baseStore, eax
        mov     ediStore, eax

;********************************************************************
; Invalidate the previous colour store (nb. writes to both fg and bg)
;********************************************************************
        mov     ax, 0FFFFh
        mov     word ptr AIxfer.bFGIndex, ax
        .erre   bBGIndex eq (bFGIndex + 1)

;********************************************************************
; Do some set up here which only needs to be done once
; AVIO CGA text WILL overpaint
;********************************************************************
        WaitQ   4
        outwQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_S)
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)
        mov     ebx,pFontDetails
        ifdef   BPP24
        mov     eax,[ebx].pFocaFont
        mov     pFocafnt,eax
        endif
        mov     cx, word ptr [ebx].usCachedFontIndex
        mov     eax,1
        shl     eax,cl
        ifndef S3
        rol     al,1                            ; Read only one cache
        endif
        outwQ   READ_ENABLE,ax                  ;  located on a bit plane
        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES   ; Expand to all planes.

;********************************************************************
; Now loop through all the clip rectangles
;********************************************************************
        ; only use cx because we do a SWAP ecx later
        mov     cx, AIxfer.cClipRects

;********************************************************************
; Get offset to first clip rectangle and use it to initialise our
; current clip rectangle pointer
;********************************************************************
        mov     eax, AIxfer.pFirstClipRect
        mov     AIxfer.pCurrentClipRect, eax

; The current font starts as the default font
        mov     _SPad.fontnum, 0h

              ;;*****************************************************
nextclip1:    ;; OUTER LOOP - For Each Clip Rectangle....
              ;;*****************************************************

        swap    ecx

;********************************************************************
; Get offset to current clip rectangle
;********************************************************************
        mov     ebx, AIxfer.pCurrentClipRect

;********************************************************************
; The offsets
;********************************************************************
ifdef   BPP24
        mov     ax, [ebx].clip_x1
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
        add     ax,2
@@:
        mov     RightClip,ax
        mov     ax, [ebx].clip_x0
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        mov     LeftClip,ax
        setclip LeftClip,[ebx].clip_y0,RightClip,[ebx].clip_y1

        mov     ax, [ebx].clip_x0
        mov     LeftClip,ax
        mov     ax, [ebx].clip_x1
        mov     RightClip,ax
        mov     ax,[ebx].clip_y0
        mov     TopClip,ax
        mov     ax,[ebx].clip_y1
        mov     BottomClip,ax

else
        setclip [ebx].clip_x0,[ebx].clip_y0,[ebx].clip_x1,[ebx].clip_y1
endif

        mov     dx, [ebx].clip_y0
        mov     _SPad.clipy0, dx

        mov     dx, [ebx].clip_x0
        mov     _SPad.clipx0, dx

        mov     ax, [ebx].clip_y1
        mov     _SPad.clipy1, ax

        mov     ax, [ebx].clip_x1
        mov     _SPad.clipx1, ax

;********************************************************************
; Now set up the start position
; First the y and x
;********************************************************************
        mov     al, AIxfer.bRow
        mul     [edi].bCellHeight
        add     ax, [edi].sYoffset
        swap    eax

        mov     al, AIxfer.bColumn
        mul     [edi].bCellWidth
        add     ax, [edi].sXoffset

;********************************************************************
; Now save them
;********************************************************************
        mov     dword ptr AIxfer.sXPosition, eax

;********************************************************************
; Hang on to the start x position
;********************************************************************
        mov     AIxfer.sRowPosition, ax

;********************************************************************
; Get the start of the block in the character buffer
;********************************************************************

        mov     ebx, AIxfer.pLVBChars

;********************************************************************
; Now lets GO!
;********************************************************************
        mov     cl, AIxfer.bDown

nextrow1:
        mov     ch, AIxfer.bAcross

;********************************************************************
; Is the top of the next row below the bottom of the current clip
; rectangle?
;********************************************************************
        mov     ax, AIxfer.sYPosition
        cmp     ax, _SPad.clipy1
        jg      lastrow1

;********************************************************************
; Is the bottom of the next row above the top of the current clip
; rectangle?
;********************************************************************
        add     al, [edi].bCellHeight
        adc     ah, 0
        cmp     ax, _SPad.clipy0
        jl      newrow1

               ;;****************************************************
nextchar1:     ;; INNER LOOP - For Each Character in the String.....
               ;;****************************************************

;********************************************************************
; Is the left edge of this character to the right of the current clip
; rectangle?
;********************************************************************
        mov     ax, AIxfer.sXPosition
        cmp     ax, _SPad.clipx1
        jg      newrow1

;********************************************************************
; Is the right edge of this character to the left of the current clip
; rectangle?
;********************************************************************
        add     al, [edi].bCellWidth
        adc     ah, 0
        cmp     ax, _SPad.clipx0
        jl      newchar1

;********************************************************************
; Save the loop counters
;********************************************************************
        push    ecx

;********************************************************************
; Get the next character and attribute byte
;********************************************************************
        mov     ecx, [ebx]

; Is it the same font as last time?
        mov     eax, ecx
        swap    eax
        .ERRNZ  MFI_FONTBITS AND 0ffffff00h
        and     eax, MFI_FONTBITS
        cmp     al, _SPad.fontnum
        jz      short samefont

;
; NEW CODE
;
; not same font - so get the FontCacheInfo pointer from al

; Store the number of the new font
        mov     _SPad.fontnum, al

        ; Make sure font is present (non-null entry in pfciTable)
        mov     edi, pAvioInfo
        mov     eax, dword ptr [edi+eax*4].pfciTable ; Get the pointer
        or      eax, eax                          ; Is it null?
        jnz     short ok_font_present
        mov     eax, baseStore            ; Yes - use base font

;            Begin
; Should reset _SPad.fontnum too
        mov     _SPad.fontnum,0
;            End

ok_font_present:
        mov     ediStore, eax            ; save pointer to cache table

;            Begin
; We must enable the correct fonts cache plane
; Always re-enable fonts cache plane every time.
        push    edx
        push    ecx
        push    ebx
        push    eax
        push    edi
        WaitQ   2
        movzx   ecx,_SPad.fontnum
        mov     eax,SIZE FONTDETAILS
        mul     ecx
        add     eax,pFontDetails
        mov     cx, word ptr [eax].usCachedFontIndex
        mov     eax,1                           
        shl     eax,cl                          ; Get font cache plane 

        ; This next rol is only for 8514 otherwise you will scramble any MFI
        ; font used on S3... ;  CMVC 87258
IFNDEF S3                                       
        rol     al,1                            ; Read only one cache
ENDIF
        outwQ   READ_ENABLE,ax                  ; located on a bit plane
        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES   ; Expand to all planes.
        pop     edi
        pop     eax
        pop     ebx
        pop     ecx
        pop     edx
;            End

samefont:
       ; Now check for inverse video
        mov     edi, ediStore            ; edi points into cache table
        test    ecx, MFI_REV_VIDEO
        jz      short normalvid

        ; The reverse video bit is set so swap background and foreground colours
        rol     ch, 4

normalvid:

;********************************************************************
; Is the foreground colour the same as it was last time?
;********************************************************************
        movzx   eax, ch
        and     al, 0Fh
        cmp     al, AIxfer.bFGIndex
        jz      short samefg1

;            Begin
        push    eax
        push    edx
        WaitQ   1
        pop     edx
        pop     eax
;            End
;********************************************************************
; Foreground colour has changed so set the new one in hardware
;********************************************************************
        mov     AIxfer.bFGIndex, al

;********************************************************************
; Get the actual colour index to use and write it out
; The lookup table is dwords so eax*4
;********************************************************************
        shl     eax,2                           ; table is dwords so *
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     edx,COLOR_1
        out     dx,ax

samefg1:
;********************************************************************
; Is the background colour the same as it was last time?
;********************************************************************
        movzx   eax, ch
        and     al, 0F0h
        cmp     al, AIxfer.bBGIndex
        jz      short samebg1

;            Begin
        push    eax
        push    edx
        WaitQ   1
        pop     edx
        pop     eax
;            End
;********************************************************************
; Background colour has changed so set the new one in hardware
;********************************************************************
        mov     AIxfer.bBGIndex, al

;********************************************************************
; Get the actual colour index to use
; The lookup table is dwords so eax/4 (eax was 16* the index)
;********************************************************************
        shr     eax, 2                          ; divide by 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     edx, COLOR_0
        out     dx,ax

samebg1:
;********************************************************************
; Get an offset from a codepoint (in cl)
;
; first save our pointer to the LVB
;********************************************************************
        push    ebx

;/*********************************************************************
;/* New code                                                          *
;/* NOTE don't need cp vector now, as we only cache 256 chars         *
;/*********************************************************************
;

        movzx   ebx, cl   ; get codepoint
        ifdef   BPP24
        mov     CodePt, bx   ; get codepoint
        endif

        ; Now get the address of the glyph definition
get_g_addr:

        mov     dx, [edi].fci_ausFontPlaneOffset[ebx*2]                ;75206
        mov     PlaneOffset,dx                                         ;75206

        mov     eax, [edi].fci_aulCachedCharOffset[ebx*4]

ifdef FIREWALLS
        ; If this offset is zero, its all gone horribly       -
        ; all chars should have been cached.
        or      eax, eax
        jnz     short @f
        int 3            ; Horrible error - chars should all be cached!
        mov     ebx, 32  ; Try again with space character !?
        jmp     get_g_addr
 @@:
 endif ; FIREWALLS

;/*********************************************************************
;/* End of new code - have address of glyph defn in eax as before     *
;/*********************************************************************

; Get back access to the LVB
        pop     ebx
        mov     edi, pAvioInfo  ; restore pointer for Avio info         ;**

;********************************************************************
; Now work out if we can do more than one character here
; dx  will be the character we are repeating (including attributes)
;********************************************************************
        mov     edx, ecx
        pop     ecx

;********************************************************************
; Save the base address on the stack for the blt later
;********************************************************************
        push    eax

;********************************************************************
; ax will be the repeat count
;********************************************************************
        mov     eax, 1

anotherchar1:
; Next cell in the LVB
        add     ebx, 4

; Do we want to do any more characters anyway
        dec     ch
        jz      short nomore1

; Is it the same as the character we've done the set up for
        cmp     edx, [ebx]
        jnz     short nomore1

; Yes it is so increase our count and loop back
        inc     eax
        jmp     short anotherchar1

nomore1:

;********************************************************************
; Note now cached chars are not in compact format, we cannot do all
; the characters in one blt, instead have a tight loop here.
;********************************************************************

        mov     chcount, eax
        mov     charinfo,edx

; Now wait for the hardware
        WaitQIdle

        WaitQ   2

; handle opaque/transparent background
        test    charinfo, MFI_TRANSPARENT
        jnz     short transparent                                       ;**

        outwQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_S)
        jmp     short done_opaque                                       ;**

transparent:
        outwQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_D)

done_opaque:

;********************************************************************
; Note now cached chars are not in compact format, we cannot do all
; the characters in one blt, instead have a tight loop here.
;********************************************************************

;********************************************************************
; Set up base address for character
;********************************************************************

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      MFI_not_24

        ; check for non greys and let them pass
        mov     fGrey,1
        movzx   eax,AIxfer.bFGIndex
        shl     eax,2                           ; table is dwords so * 4
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     _Shadow8514Regs.Color_1,eax
        movzx   eax,AIxfer.bBGIndex
        shr     eax,2                           ; was * 16 so div by four
        add     eax, dword ptr _pAVIOColorXlate ; add the table start
        mov     eax, [eax]                      ; get the color value
        mov     _Shadow8514Regs.Color_0,eax
        rol     eax,8                           ; XXBBGGRR -> BBGGRRXX
        mov     al,ah                           ; BBGGRRRR
        ror     eax,8                           ; RRBBGGRR
        xor     al,ah                           ; GG == RR?
        jnz     not_gray                        ; no, not gray
        shr     eax,16                          ; 0000RRBB
        xor     al,ah                           ; RR == BB?
        jnz     not_gray                        ; no, not gray
        mov     eax,_Shadow8514Regs.Color_1
        rol     eax,8                           ; XXBBGGRR -> BBGGRRXX
        mov     al,ah                           ; BBGGRRRR
        ror     eax,8                           ; RRBBGGRR
        xor     al,ah                           ; GG == RR?
        jnz     not_gray                        ; no, not gray
        shr     eax,16                          ; 0000RRBB
        xor     al,ah                           ; RR == BB?
        jnz     not_gray                        ; no, not gray
        jmp     MFI_not_24
not_gray:
        pop     eax                             ; Restore the VRAM pointer
        push    ecx                             ; Save Loop Counters

        mov     eax,chcount
        push    eax

        mov     fGrey,0
        mov     x_inc,0
        mov     si, AIxfer.sXPosition
        swap    esi
        mov     si, AIxfer.sYPosition
        swap    esi                             ; get in y-x format

do_next_mfi_24:
        mov     edi, pAvioInfo

        mov     x_src,0                 ; assume no clipping
        mov     y_src,0
        mov     TimeAround,0
        mov     eax,esi
        movzx   edx,[edi].bCellWidth    ; ax = x dest  dx = blt width
        mov     usPels,dx               ; assume full char width
        cmp     ax,LeftClip             ; any clipping on left?
        jge     MFI_LeftOK              ; no, check right edge
        add     ax,dx                   ; ax = right edge of blt
        sub     ax,LeftClip             ; are we totally clipped out?
        jle     MFI_done_24_char        ; yes, don't bother
        mov     usPels,ax               ; new blt width
        mov     dx,ax                   ; save for later
        mov     ax,LeftClip
        sub     ax,si
        mov     x_src,ax
        add     si,ax                   ; new x dest
        mov     ax,si                   ; check right edge
MFI_LeftOK:
        cmp     ax,RightClip            ; are we totally clipped out?
        jg      MFI_done_24_char        ; yes
        add     ax,dx                   ; dx has blt width
        sub     ax,RightClip
        jle     MFI_RightOK
        dec     ax
        sub     usPels,ax
        jz      MFI_done_24_char
MFI_RightOK:
        shr     eax,16                  ; ax = y dest
        cmp     ax,BottomClip           ; are we totaly clipped out?
        jg      MFI_done_24_char        ; yes
        movzx   edx,[edi].bCellHeight
        sub     ax,TopClip
        jge     MFI_TopOK
        neg     ax
        sub     dx,ax                   ; new height
        jle     MFI_done_24_char
        mov     y_src,ax
        rol     esi,16
        add     si,ax
        rol     esi,16
MFI_TopOK:
        mov     eax,esi
        shr     eax,16
        add     ax,dx                   ; ax = bottom of blt
        sub     ax,BottomClip
        jle     MFI_BottomOK
        dec     ax
        sub     dx,ax
        jle     MFI_done_24_char
MFI_BottomOK:
        mov     usHeight,dx

        movzx   eax, [edi].bCellWidth
MFI24TopLoop:
        sub     ax,8
        jge     @f
        xor     ax,ax                   ; last time around
@@:
        push    ax

        mov     ax,x_src
        cmp     ax,8
        jge     MFISkipBlt

        push    ax                      ; bits into first byte

        push    ONE_BPP                         ; format

        movzx   edx,usHeight
        dec     edx                     ; make zero-based
        push    edx                     ; height

        mov     eax,7                   ; do one byte column
        push    eax                     ; bmap width

        movzx   edx,usPels
        mov     ax,dx
        add     ax,x_src
        sub     ax,8
        jle     @f
        sub     dx,ax
@@:
        sub     usPels,dx               ; get usPels ready for next time around
        dec     edx                     ; Make zero-based
        push    edx                     ; blt width

        swap    esi                     ; get in x-y format
        push    esi                     ; vram dest

        ; now get the address of the char definition
        push    ebx
        movzx   ebx, CodePt                      ; get codepoint
        mov     eax, [edi].pfciTable
ifdef FULL_ADDRESS
        mov     eax, [eax].fci_apCharDef[ebx*4]
else ; ndef FULL_ADDRESS
        movzx   eax, word ptr [eax].fci_apCharDef[ebx*2]
        add     eax, pFocafnt
endif ; ndef FULL_ADDRESS
        mov     ebx, [eax]
        movzx   eax,[edi].bCellHeight
        mul     TimeAround
        add     eax,ebx
        add     eax, pFocafnt

        add     ax,y_src

        pop     ebx

        push    eax                     ; memory source
        call    _Copy24MonoToVRAM
        add     esp,26

        swap    esi                     ; get in y-x format

MFISkipBlt:

        inc     TimeAround
        mov     ax,x_src
        cmp     ax,8                    ; did we do anything?
        jl      MFISubXSrc              ; yes
        sub     ax,8                    ; no, update x_src and try again
        mov     x_src,ax
        jmp     @f
MFISubXSrc:
        sub     si,x_src                ; subtract what we added for x_src
        mov     x_src,0                 ; we are through with the x offset
        add     si,8                    ; get ready for next byte
@@:
        pop     ax
        or      ax,ax                   ; any pels left?
        jnz     MFI24TopLoop            ; yes, go back around
        movzx   ecx,TimeAround          ; no, clean up and go on
@@:
        sub     si,8                    ; put si back to where we found it
        loop    @b


MFI_done_24_char:

        sub     si,x_src                ; set esi back to what
        rol     esi,16                  ;  it was before clipping
        sub     si,y_src
        rol     esi,16

        movzx   ax,byte ptr [edi].bCellWidth                                    ;**
        mov     di,ax
        mov     cx,ax ; Note ecx contains width

        jmp     done_mfi_char
MFI_not_24:
endif

        WaitQ   4
        pop     eax             ; Restore the VRAM pointer
        push    ecx             ; Save Loop Counters

        calc8514xy      eax
        mov     ecx,edx
        outwQ   Y0,ax
        mov     eax,ecx
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
endif
        outwQ   X0,ax

        pop     ecx             ; Restore Loop Counters

;********************************************************************
; Reset the operating dimension width & height
;********************************************************************
        xor     eax,eax
        mov     al, [edi].bCellHeight
        dec     al
        outwQ   LY,ax

        mov     al, [edi].bCellWidth
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        ; the cell width is already one based.
        mov     x_inc,0
        movzx   di,al
        mov     dx,3
        mul     dx
@@:
endif
        dec     al
        outwQ   LX,ax

        inc     eax
        push    ecx
        mov     ecx,eax ; Note ecx contains width

;********************************************************************
; Set up the coords in edx
;********************************************************************
        mov     si, AIxfer.sYPosition
        swap    esi
        mov     si, AIxfer.sXPosition

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     ax,si
        mov     dx,3
        mul     dx
        mov     si,ax
@@:
endif

        mov     eax,chcount
        push    eax

do_next_blt_4:
;********************************************************************
; Set the position in the destination
;********************************************************************
        WaitQ   2

        outwQ   X1,si
        swap    esi
        outwQ   Y1,si
        swap    esi

        ; start 75206
        WaitQ   2
        mov     dx, PlaneOffset
        cmp     dx,-1                           ; are we in 16 bit color?
        jz      @f                              ; no, the read plane is set
        push    ebx                             ; yes, we might have to go to 
        push    ecx                             ;  plane Index+8 or back to Index
        and     dx,1                            ; just in case
        shl     dx,3
        mov     ebx,pFontDetails
        mov     cx, word ptr [ebx].usCachedFontIndex
        add     cx,dx
        mov     eax,1
        shl     eax,cl
        outwQ   READ_ENABLE,ax                  ; located on a bit plane.
        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES   ; Expand to all planes.
        pop     ecx
        pop     ebx
@@:
        ; end 75206

;********************************************************************
; Now, a bacon, lettuce & tomato please.
;********************************************************************
        WaitQ   1
        outwQ   CMD_FLAGS,CMD_DRAWTEXT

ifdef BPP24
done_mfi_char:
endif

;********************************************************************
; More chars?
;********************************************************************
        add     si, cx  ; get next position
        ifdef   BPP24
        add     x_inc,di
        endif

ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        test    fGrey,1
        jnz     @f

        dec     chcount
        jnz     do_next_mfi_24
        jmp     dec_done1
@@:
        dec     chcount
        jnz     do_next_blt_4
dec_done1:
else
        dec     chcount
        jnz     do_next_blt_4
endif

ifdef BPP24
        mov     edi,pAvioInfo
endif
; Now check for overstrike and/or underscore
; edx holds the character cell
        test    charinfo, MFI_USCORE
        jz      nouscore                                               ;**

        WaitQIdle

        WaitQ   7

; there is an underscore on the last character(s) printed
        mov     eax, dword ptr [AIxfer.sXPosition]
        swap    eax

; the underscore is a solid line two pels form the bottom of the cell
        add     al, [edi].bCellHeight                                   ;**
        adc     ah, 0
        sub     ax, 2
        outwQ   Y0,ax
        swap    eax
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     dx,3
        mul     dx
@@:
endif
        outwQ   X0,ax

        ; Set the mode to use foreground color for the underscore.
        ; MRC 65080

        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE)

; refresh ax (the repeat count)
        pop     eax
        push    eax

; set the operating dimensions to underscore ax characters
        mul     [edi].bCellWidth                                        ;**
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     x_inc,0
        mov     dx,3
        mul     dx
@@:
endif
        dec     al
        outwQ   LX,ax
        outwQ   LY,0
        outwQ   CMD_FLAGS,CMDSOLID

        ; Set the mode back to plane mode for Fonts
        ; MRC 65080

        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)

nouscore:
IFDEF OVERSTRIKE
        test    charinfo, MFI_OSTRIKE
        jz      noostrike

        WaitQIdle

        WaitQ   5

; there is an overstrike on the last character(s) printed
; an overstrike is a solid line through the midlle of the cell
        sub     ax, ax
        mov     al, [edi].bCellHeight                                   ;**
        shr     al, 1
        add     ax, AIxfer.sYPosition
        outwQ   Y1,ax
        mov     ax, AIxfer.sXPosition
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
endif
        outwQ   X1,ax

; refresh ax (the repeat count)
        pop     ax
        push    ax

; set the operating dimensions to do overstrike ax characters
        mul     byte ptr [edi].bCellWidth                               ;**
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     x_inc,0
        mov     dx,3
        mul     dx
@@:
endif
        dec     al
        outwQ   LX,ax
        outwQ   LY,0
        outwQ   CMD_FLAGS,CMDSOLID

noostrike:
ENDIF
        pop     eax             ; Remove repeat count from stack.

;********************************************************************
; Save final x coord
;********************************************************************
        ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     si,AIxfer.sXPosition
        add     si,x_inc
@@:
        endif
        mov     AIxfer.sXPosition, si
        pop     ecx

;********************************************************************
; Are there any more characters?
;********************************************************************
        ; @DMS put here in case we change colors
        WaitQ   2
        cmp     ch, 0
        jnz     nextchar1   ;;;; END INNER LOOP - For Each Char.....

;********************************************************************
; A new row
;********************************************************************
newrow1:
        dec     cl
        jz      short lastrow1

;********************************************************************
; more rows so adjust y coordinate and retrieve x coordinate for
; start of line
;********************************************************************
        xor     eax,eax
        mov     al, [edi].bCellHeight
        add     ax, AIxfer.sYPosition
        mov     AIxfer.sYPosition, ax
        mov     ax, AIxfer.sRowPosition
        mov     AIxfer.sXPosition, ax

;********************************************************************
; allow for any characters which we might have missed by adding
; an 2*cl to our pointer to the LVB
;********************************************************************
        xor     eax, eax
        mov     al, ch
        shl     ax, 2
        add     ebx, eax

;********************************************************************
; now move to the position in the LVB corresponding to the start of
; the next row..
; adding the .bufwidth takes us to the end of the next line then
; subtracting .across takes us back to the start of the next line
;********************************************************************
        sub     edx,edx
        mov     dl, AIxfer.bBufferWidth

        ; Change to increment by four bytes per char instead of 2
        ; MRC 65080

        shl     edx,2
        add     ebx, edx
        sub     edx,edx
        mov     dl, AIxfer.bAcross
        shl     edx,2
        sub     ebx, edx
        jmp     nextrow1

lastrow1:
;********************************************************************
; see if there is a new clip rectangle
;********************************************************************
        swap    ecx
        dec     cx
        jz      short lastclip1
        mov     eax, AIxfer.pCurrentClipRect
        add     eax, len_clip_rect
        mov     AIxfer.pCurrentClipRect, eax

                            ;;**************************************
        jmp     nextclip1   ;; END OUTER LOOP - For Each Clip Rect.....
                            ;;**************************************

newchar1:
;********************************************************************
; we get to here when the characters are still to the left of the
; current clip rectangle so we haven't started printing them yet
;********************************************************************
        xor     eax, eax
        mov     al, [edi].bCellWidth
        add     AIxfer.sXPosition, ax

        add     ebx, 4

;********************************************************************
; are there any more characters?
;********************************************************************
        dec     ch
        jnz     nextchar1
        jmp     newrow1

lastclip1:
pmmfiexit:
;********************************************************************
; tidy up and go home
;********************************************************************
        WaitQ   1
        outwQ   READ_ENABLE,READ_ALL_PLANES
        ifndef  S3
        setclip 0,0,SCR_8514_WIDTH-1,SCR_8514_HEIGHT-1
        else
        setclip 0,0,SCR_S3_WIDTH-1,SCR_S3_HEIGHT-1
        endif

cEnd

ENDIF ; _8514

IFNDEF _8514

;***********************************************************************
;
; Function: AVIOScroll - XGA Version
;
; Called by:
;
; This code is 386 only.
;***********************************************************************

        align   4
cProc AVIOScroll,<PUBLIC>,<edi,esi,ebx>
        parmD   pAvioInfo

cBegin
        pushxga

; Is there anything to do?
        cmp     AIxfer.bAcross, 0h
        jz      noscroll
        cmp     AIxfer.bDown, 0h
        jz      noscroll

; There is something to do so set-up
        movxga  _pRealXGARegs
        mov     edi, pAvioInfo                                          ;**

; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect                            ;**

; Set up the destination bitmap (will be the screen)
        waitshort

; Select the mask map
        memregwrite     pi_map_index_M, SEL_MASK_MAP

; The offsets
        mov     ax, [ebx].clip_y0                                       ;**
        swap    eax
        mov     ax, [ebx].clip_x0                                       ;**

; Write them out to the hardware
        memregwrite     mask_org, eax

; The height
        mov     ax, [ebx].clip_y1                                       ;**
        sub     ax, [ebx].clip_y0                                       ;**
        swap    eax

; The width
        mov     ax, [ebx].clip_x1                                       ;**
        sub     ax, [ebx].clip_x0                                       ;**

; Write them out to hardware
        memregwrite     pi_map_size_M, eax

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest                                    ;**
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; physical address
        mov     eax, [ebx+phys_addr]                                    ;**
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     ax, [ebx+hw_height]                                     ;**
        swap    eax
        mov     ax, [ebx+hw_width]                                      ;**
        memregwrite     pi_map_size_A, eax

; format
        mov     ax, [ebx+hw_format]                                     ;**
        memregwrite     pi_map_format_A, al

; Set mixes to overpaint
        memregwrite     fg_mix, 03h
        memregwrite     bg_mix, 03h
        memregwrite     colour_comp_fun, COLCOMP_ALWAYS

; Get the source and destination start position (row and column are
; byte length)
        ; we assume we can pick up word values and get point values
        .ERRE   bSourceRow eq (bSourceColumn + 1)
        .ERRE   bDestRow eq (bDestColumn + 1)

        mov     bx, word ptr AIxfer.bSourceColumn
        mov     cx, word ptr AIxfer.bDestColumn

; Clear the octant mask
        mov     dl, 0

; set the source and destination x positions
        mov     al, bl
        mul     [edi].bCellWidth                                        ;**
        mov     AIxfer.usXSource, ax

        mov     al, cl
        mul     [edi].bCellWidth                                        ;**
        mov     AIxfer.usXDest, ax

; which way do we want the blt to go?
        cmp     bl, cl
        jae     short xpositive                                         ;**

; the source is to the left of the destination so we want to blt from
; right to left so adjust the start position and the octant value
        mov     al, AIxfer.bAcross
        mul     [edi].bCellWidth                                        ;**
        dec     ax
        add     AIxfer.usXSource, ax

        add     AIxfer.usXDest, ax

        or      dx, OCT_DX_BIT

xpositive:
; set the source and destination y positions
        mov     al, bh
        mul     [edi].bCellHeight                                       ;**
        mov     AIxfer.usYSource, ax

        mov     al, ch
        mul     [edi].bCellHeight                                       ;**
        mov     AIxfer.usYDest, ax

; which way do we want to blt?
        cmp     bh, ch
        jae     short ypositive                                         ;**

; the source is above the destination so we want to blt from bottom
; to top so adjust the start postion and the octant value
        mov     al, AIxfer.bDown
        mul     [edi].bCellHeight                                       ;**
        dec     ax
        add     AIxfer.usYSource, ax

        add     AIxfer.usYDest, ax

        or      dx, OCT_DY_BIT
ypositive:

; Set hardware dimensions in eax
        mov     al, AIxfer.bDown
        mul     [edi].bCellHeight                                       ;**
        dec     ax
        swap    eax

        mov     al, AIxfer.bAcross
        mul     [edi].bCellWidth                                        ;**
        dec     ax

; now set up the start positions (allowing for the offsets) in ebx and ecx
        mov     cx, AIxfer.usYDest
        add     cx, [edi].sYoffset                                      ;**
        swap    ecx
        mov     cx, AIxfer.usXDest
        add     cx, [edi].sXoffset                                      ;**

        mov     bx, AIxfer.usYSource
        add     bx, [edi].sYoffset                                      ;**
        swap    ebx
        mov     bx, AIxfer.usXSource
        add     bx, [edi].sXoffset                                      ;**

; if the source x is negative then make it zero and adjust the destination x
; and the blt width accordingly
        test    bx, 8000h
        jz      short @F                                                ;**
        sub     cx, bx
        sub     ax, bx
        sub     bx, bx

@@:
; send the source and destination coordinates and the dimensions to the h/w
        memregwrite     src_map, ebx
        memregwrite     dest_map, ecx
        memregwrite     dimensions, eax

; and do the blt using the octant value we have just worked out
        mov     eax, AVIO_scrollblt
        or      al, dl
        memregwrite     pixel_op, eax

noscroll:
        popxga
cEnd

ELSE ; _8514 Version

;***********************************************************************
;
; Function: AVIOScroll - 8514
;
; Called by:
;
; This code is 386 only.
;***********************************************************************

        align   4
cProc AVIOScroll,<PUBLIC>,<edi,esi,ebx>
        parmD   pAvioInfo
        localW  src_x
        localW  src_y
        localW  dst_x
        localW  dst_y
        localW  usWidth
        localW  usHeight
        localW  BltDirection
        ifdef   BPP24
        localW  RightClip
        localW  LeftClip
        endif

cBegin

; Is there anything to do?
        cmp     AIxfer.bAcross, 0h
        jz      noscroll
        cmp     AIxfer.bDown, 0h
        jz      noscroll

; There is something to do so set-up
        mov     edi, pAvioInfo                                          ;**

; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect                            ;**

ifdef   BPP24
        mov     ax, [ebx].clip_x1
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
        add     ax,2
@@:
        mov     RightClip,ax
        mov     ax, [ebx].clip_x0
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        mov     LeftClip,ax
        setclip LeftClip,[ebx].clip_y0,RightClip,[ebx].clip_y1
else
        setclip [ebx].clip_x0,[ebx].clip_y0,[ebx].clip_x1,[ebx].clip_y1
endif

; Set mixes to overpaint
        WaitQ   2
        outwQ   FUNCTION_1,(FUNC_2OP_COPY+FUNC_S)
        outwQ   FUNCTION_0,(FUNC_2OP_COPY+FUNC_S)

; Get the source and destination start position (row and column are
; byte length)
        ; we assume we can pick up word values and get point values
        .ERRE   bSourceRow eq (bSourceColumn + 1)
        .ERRE   bDestRow eq (bDestColumn + 1)

        mov     bx, word ptr AIxfer.bSourceColumn
        mov     cx, word ptr AIxfer.bDestColumn

; Clear the octant mask
        mov     BltDirection, 0

; set the source and destination x positions
        mov     al, bl
        mul     [edi].bCellWidth                                        ;**
        mov     AIxfer.usXSource, ax

        mov     al, cl
        mul     [edi].bCellWidth                                        ;**
        mov     AIxfer.usXDest, ax

; which way do we want the blt to go?
        cmp     bl, cl
        jae     short xpositive                                         ;**

; the source is to the left of the destination so we want to blt from
; right to left so adjust the start position and the octant value
        mov     al, AIxfer.bAcross
        mul     [edi].bCellWidth                                        ;**
        dec     ax
        add     AIxfer.usXSource, ax

        add     AIxfer.usXDest, ax
        jmp     short @F

xpositive:
        or      BltDirection, CMD_DX

@@:
; set the source and destination y positions
        mov     al, bh
        mul     [edi].bCellHeight                                       ;**
        mov     AIxfer.usYSource, ax

        mov     al, ch
        mul     [edi].bCellHeight                                       ;**
        mov     AIxfer.usYDest, ax

; which way do we want to blt?
        cmp     bh, ch
        jae     short ypositive                                         ;**

; the source is above the destination so we want to blt from bottom
; to top so adjust the start postion and the octant value
        mov     al, AIxfer.bDown
        mul     [edi].bCellHeight                                       ;**
        dec     ax
        add     AIxfer.usYSource, ax

        add     AIxfer.usYDest, ax
        jmp     short @F

ypositive:
        or      BltDirection, CMD_DY

@@:
; Set hardware dimensions in eax
        mov     al, AIxfer.bDown
        mul     [edi].bCellHeight                                       ;**
        dec     ax
        mov     usHeight,ax

        mov     al, AIxfer.bAcross
        mul     [edi].bCellWidth                                        ;**
        dec     ax
        mov     usWidth,ax

; now set up the start positions (allowing for the offsets) in ebx and ecx
        mov     cx, AIxfer.usYDest
        add     cx, [edi].sYoffset                                      ;**
        mov     dst_y,cx

        mov     cx, AIxfer.usXDest
        add     cx, [edi].sXoffset                                      ;**
        mov     dst_x,cx

        mov     bx, AIxfer.usYSource
        add     bx, [edi].sYoffset                                      ;**
        mov     src_y,bx

        mov     bx, AIxfer.usXSource
        add     bx, [edi].sXoffset                                      ;**
        mov     src_x,bx

; if the source x is negative then make it zero and adjust the destination x
; and the blt width accordingly
        test    bx, 8000h
        jz      short @F                                                ;**
        sub     dst_x, bx
        sub     src_x, bx
        sub     usWidth, bx

@@:
; send the source and destination coordinates and the dimensions to the h/w

        WaitQIdle

        WaitQ   8
ifdef   BPP24
        mov     ax,usWidth
        test    [_DDT],USE_24BPP
        jz      @f
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
@@:
        outwQ   LX,ax
else
        outwQ   LX,usWidth
endif
        outwQ   LY,usHeight

ifdef   BPP24
        mov     ax,src_x
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        outwQ   X0,ax
else
        outwQ   X0,src_x
endif
        outwQ   Y0,src_y

ifdef   BPP24
        mov     ax,dst_x
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        outwQ   X1,ax
else
        outwQ   X1,dst_x
endif
        outwQ   Y1,dst_y

; and do the blt using the octant value we have just worked out
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE)
        mov     eax,CMDSRCSCR
        or      ax,BltDirection
        outwQ   CMD_FLAGS,ax

        ifndef  S3
        setclip 0,0,SCR_8514_WIDTH-1,SCR_8514_HEIGHT-1
        else
        setclip 0,0,SCR_S3_WIDTH-1,SCR_S3_HEIGHT-1
        endif

noscroll:

cEnd

ENDIF ; _8514 Version



IFNDEF _8514

;***********************************************************************
;
; Function: AVIOCursor - XGA Version
;
; Called by: eddvupdc.c
;
; This code inverts the rectangle specified by parameters passed in via
; AIxfer taking account of all current clip rectangles.  Note that we
; don't bother with intersecting clip rectangles etc because a) the
; cursor is only wee anyway so if it's totally clipped out it's not
; going to take up much time being 'drawn' and b) because the cursor is
; only on when the AVIO window has the focus - therefore only one clip
; rectangle (and (a) never happens!)
;
; This code is 386 only.
;***********************************************************************

        align   4
cProc AVIOCursor,<PUBLIC>,<esi,edi,ebx>
cBegin
        pushxga

; Get the hardware registers address
        movxga  _pRealXGARegs

; Set up the destination bitmap (will be the screen)
        waitshort

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest                                    ;**
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; physical address
        mov     eax, [ebx+phys_addr]                                    ;**
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     ax, [ebx+hw_height]                                     ;**
        swap    eax
        mov     ax, [ebx+hw_width]                                      ;**
        memregwrite     pi_map_size_A, eax

; format
        mov     ax, [ebx+hw_format]                                     ;**
        memregwrite     pi_map_format_A, al

; Always invert foreground and background
        memregwrite     fg_mix, INVERT_DEST
        memregwrite     bg_mix, INVERT_DEST
        memregwrite     colour_comp_fun, COLCOMP_ALWAYS

; Now loop through all the clip rectangles
        mov     cx, AIxfer.cClipRects

; Get offset to first clip rectangle and us it to start our running total
        mov     eax, AIxfer.pFirstClipRect                              ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**

nextclip2:
; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect                            ;**

; Wait on the hardware before going any further
        waitshort

; We want the mask map
        memregwrite     pi_map_index_M, SEL_MASK_MAP

; The offsets
        mov     ax, [ebx].clip_y0                                       ;**
        swap    eax
        mov     ax, [ebx].clip_x0                                       ;**

; Write them out to the hardware
        memregwrite     mask_org, eax

; The height
        mov     ax, [ebx].clip_y1                                       ;**
        sub     ax, [ebx].clip_y0                                       ;**
        swap    eax

; The width
        mov     ax, [ebx].clip_x1                                       ;**
        sub     ax, [ebx].clip_x0                                       ;**

; Write them out to hardware
        memregwrite     pi_map_size_M, eax

; Now set up the start position
        .ERRE   usCursorY eq (usCursorX + 2)
        mov     eax, dword ptr AIxfer.usCursorX
        memregwrite     dest_map, eax

; And the operating dimensions
        mov     ax, AIxfer.usCursorL
        memregwrite     dim1, ax

        mov     ax, AIxfer.usCursorH
        memregwrite     dim2, ax

; Now a solid blt (like the underline/overstrike)
        memregwrite     pixel_op, AVIO_usblt

; A new clip rectangle
        dec     cx
        jz      short lastclip2                                         ;**
        mov     eax, AIxfer.pCurrentClipRect                            ;**
        add     eax, len_clip_rect                                      ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**
        jmp     nextclip2

lastclip2:
        popxga
cEnd

ELSE ; _8514

;***********************************************************************
;
; Function: AVIOCursor - 8514 Version
;
; Called by: eddvupdc.c
;
; This code inverts the rectangle specified by parameters passed in via
; AIxfer taking account of all current clip rectangles.  Note that we
; don't bother with intersecting clip rectangles etc because a) the
; cursor is only wee anyway so if it's totally clipped out it's not
; going to take up much time being 'drawn' and b) because the cursor is
; only on when the AVIO window has the focus - therefore only one clip
; rectangle (and (a) never happens!)
;
; This code is 386 only.
;***********************************************************************

        align   4
cProc AVIOCursor,<PUBLIC>,<esi,edi,ebx>
        ifdef   BPP24
        localW  RightClip
        localW  LeftClip
        endif
cBegin
        WaitQIdle

        WaitQ   6

; set up the destination bitmap (as pixel map A)
        mov     ebx, AIxfer.pbmhDest                                    ;**

;            physical address
;                  mov     eax, dword ptr AIxfer.usCursorX
;                  outwQ   X1,ax
;                  outwQ   X0,ax
;                  swap    eax
;                  outwQ   Y1,ax
;                  outwQ   Y0,ax

; Always invert foreground and background
        mov     ax,(FUNC_2OP_COPY+FUNC_ND)
        outwQ   FUNCTION_1,ax
        outwQ   FUNCTION_0,ax

; Now loop through all the clip rectangles
        mov     cx, AIxfer.cClipRects

; Get offset to first clip rectangle and us it to start our running total
        mov     eax, AIxfer.pFirstClipRect                              ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**

nextclip2:
; Get offset to current clip rectangle
        mov     ebx, AIxfer.pCurrentClipRect                            ;**

; The offsets
ifdef   BPP24
        mov     ax, [ebx].clip_x1
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
        add     ax,2
@@:
        mov     RightClip,ax
        mov     ax, [ebx].clip_x0
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        mov     LeftClip,ax
        setclip LeftClip,[ebx].clip_y0,RightClip,[ebx].clip_y1
else
        setclip [ebx].clip_x0,[ebx].clip_y0,[ebx].clip_x1,[ebx].clip_y1
endif

; physical address                              ;          
        mov     eax, dword ptr AIxfer.usCursorX ;          
ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
endif
        outwQ   X1,ax                           ;          
        outwQ   X0,ax                           ;          
        swap    eax                             ;          
        outwQ   Y1,ax                           ;          
        outwQ   Y0,ax                           ;          

; And the operating dimensions
        WaitQ   4
ifdef   BPP24
        mov     ax,AIxfer.usCursorL
        test    [_DDT],USE_24BPP
        jz      @f

        mov     dx,3
        mul     dx
@@:
        outwQ   LX,ax
else
        outwQ   LX,AIxfer.usCursorL
endif
        outwQ   LY,AIxfer.usCursorH

; Now a solid blt (like the underline/overstrike)
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMDSOLID

; A new clip rectangle
        dec     cx
        jz      short lastclip2                                         ;**
        mov     eax, AIxfer.pCurrentClipRect                            ;**
        add     eax, len_clip_rect                                      ;**
        mov     AIxfer.pCurrentClipRect, eax                            ;**
        jmp     nextclip2

lastclip2:
        ifndef  S3
        setclip 0,0,SCR_8514_WIDTH-1,SCR_8514_HEIGHT-1
        else
        setclip 0,0,SCR_S3_WIDTH-1,SCR_S3_HEIGHT-1
        endif
cEnd

ENDIF

;/*********************************************************************/
;/* New functions to ensure all chars in the rect that is about to be */
;/* drawn are cached.  Different versions for 2, 4 byte cells         */
;/*********************************************************************/

;* defect 70246  Made changes as we were not looking at the proper cache
;*               table.  The changes are noted by my initials  vcb

        align   4
cProc update_cache_charrect_4,<PUBLIC>,<esi,edi,ebx>
        parmD   pFontDetails
        parmD   pAvioInfo

        localD  ulRowStep                                               ;**
        localD  ulLastFontNum
        localD  LastUsedFontNum
        localD  ulLastChar


cBegin
        ; pAvioInfo.pfciTable contains 4 pointers into the FontCache table
        ; for the four fonts 0-3

        mov     ulLastChar, -1    ; force setup first time

        ; setup LVB increments/pointer

        mov     esi, AIxfer.pLVBChars   ; Top left of rectangle in LVB
        mov     edi, pAvioInfo
        mov     edi, [edi].pfciTable    ; Base font CacheTable entry

        xor     ecx, ecx
        mov     ulLastFontNum, ecx      ; default to base font
        mov     LastUsedFontNum, ecx    ; default to base font

        ; calculate step from end of one row to start of next
        movzx   eax, AIxfer.bBufferWidth ; LVB width
        sub     al, AIxfer.bAcross
        shl     eax, 2                  ; 4* number of chars
        mov     ulRowStep, eax

        mov     ch, AIxfer.bDown
next_row_4:
        mov     cl, AIxfer.bAcross
next_column_4:

        mov     eax, [esi]              ; Get extended char
        and     eax, MFI_CHARMASK       ; mask out attribute bits
        cmp     eax, ulLastChar
        jz      short char_is_cached

        mov     ulLastChar, eax
        ; different char
        ; is it in same font?
        mov     edx, eax
        shr     edx,16

        and     edx, MFI_FONTBITS        ; =3
        cmp     edx, ulLastFontNum
        jz      short same_font
        mov     ulLastFontNum, edx

        ; This font may not exist (ie NULL pfciTable entry )
        ; If so, use default
        mov     LastUsedFontNum, edx
        mov     edi, pAvioInfo
        mov     edx, dword ptr [edi+edx*4].pfciTable
        or      edx, edx        ; Is this entry null?
        jnz     short ok_4_font
        mov     edi, pAvioInfo  ; Yes: use default
        mov     edx, dword ptr [edi].pfciTable                ;vcb

        ; @78461 It is possible the the default font table is trash, so return
        ; an error to get it reloaded
        or      edx,edx                                       ;@78461
        jnz     short valid_table_entry                       ;@78461
        xor     eax,eax                                       ;@78461
        jmp     error_exit                                    ;@78461
                                                              ;@78461
valid_table_entry:                                            ;@78461
        mov     LastUsedFontNum, 0


        ; get the fonttable entry for this font
ok_4_font:
;            Begin
;        mov     edi, dword ptr [edi].pfciTable               ;vcb
        mov     edi, edx                                      ;vcb
;            End

same_font:
        movzx   ebx, al         ; Move codepoint into EBX

        ; Now get glyph definition address
        mov     eax, [edi].fci_aulCachedCharOffset[ebx*4]
        or      eax, eax
        jnz     short char_is_cached

        ; Ok, this is not cached, so cache it.
        push    esi
        push    edi
        push    ecx

        ; CacheCharacter takes ( chCodePoint, pFontDetails ) as parameters

        mov     eax, SIZE FONTDETAILS
        mul     LastUsedFontNum
        add     eax, pFontDetails

        push    eax     ; The FONTDETAILS for this font
        push    ebx      ; Codepoint
        call    _eddt_CacheCharacter
        add     esp, 8

        pop     ecx     ; restore registers
        pop     edi
        pop     esi

        or      ax, ax  ; CHANGE this to return a ULONG not a USHORT!
        jnz     short char_is_cached                                    ;**

        ; Allow the caching code to tidy up
        call    _eddt_TidyUpAfterCaching

        ; Indicate failure
        xor     eax,eax
        jmp     short error_exit                                        ;**

char_is_cached:
        ; now do next char..
        add     esi, 4                                                  ;**
        dec     cl
        jnz     next_column_4

        add     esi, ulRowStep          ; end of row to start of next   ;**
        dec     ch
        jnz     next_row_4

        ; Finished - allow the caching code to tidy up
        call    _eddt_TidyUpAfterCaching

        ; return OK
        mov     eax, 1
error_exit:

cEnd




;/*********************************************************************/
;/* now same function for 2-byte AVIO. only one font                  */
;/*********************************************************************/

        align   4
cProc update_cache_charrect_2,<PUBLIC>,<edi,esi,ebx>

        parmD   pFontDetails
        parmD   pAvioInfo

        localD  ulRowStep
        localD  ulLastChar

cBegin
        mov     ulLastChar, -1

        ; setup LVB increments/pointer

        mov     esi, AIxfer.pLVBChars   ; top left of rect
        mov     edi, pAvioInfo
        mov     edi, [edi].pfciTable    ; base font in cache table

;Defect 53016 Start ****************************************************

        ;If the cache table is NULL, return ERROR to indicate that the
        ; font has been trashed, which will cause the font to be located
        ; and then update_cache_charrect_2 to be called again.

        cmp     edi,0
        jnz     @f                      ;Indicate failure

        xor     eax,eax
        jmp     short error_exit_2
@@:

;Defect 53016 End ******************************************************

        ; calculate step from end of one row to start of next
        movzx   eax, AIxfer.bBufferWidth ; LVB width
        sub     al, AIxfer.bAcross
        shl     eax, 1                  ; 2 * number of chars
        mov     ulRowStep, eax

        mov     ch, AIxfer.bDown

next_row_2:
        mov     cl, AIxfer.bAcross

next_column_2:
        movzx   eax, byte ptr [esi]     ; Get char
        cmp     eax, ulLastChar
        jz      short char2_is_cached

        ; different char
        mov     ulLastChar, eax
        mov     ebx, eax                ; Codepoint

        mov     edx, dword ptr [edi].fci_aulCachedCharOffset.[ebx*4]
                                        ; Get address of glyph definition
        or      edx, edx
        jnz     short char2_is_cached

        ; Ok, this is not cached, so cache it.
        push    ecx     ; save the counts

        ; Parameters ( chCodePoint, pFontDetails ) pushed.
        mov     eax, pFontDetails       ; FONTDETAILS for base font
        push    eax
        push    ebx                     ; codepoint
        call    _eddt_CacheCharacter
        add     esp, 8

        pop     ecx      ; Restore registers

        or      ax, ax  ; should return a ULONG but is actually a USHORT !
        jnz     short char2_is_cached

        ; Allow the caching code to tidy up
        call    _eddt_TidyUpAfterCaching

        ; Indicate failure
        xor     eax,eax
        jmp     short error_exit_2

char2_is_cached:
        ; now do next char..
        add     esi, 2
        dec     cl
        jnz     next_column_2

        add     esi, ulRowStep          ; end of row to start of next
        dec     ch
        jnz     next_row_2

        ; Finished - Allow the caching code to tidy up
        call    _eddt_TidyUpAfterCaching

        ; return OK
        mov     eax, 1

error_exit_2:
cEnd


_TEXT           ends

END
