File:  [WindowsNT SDKs] / ntddk / src / video / displays / vga / i386 / glyphblt.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

;---------------------------Module-Header------------------------------;
; Module Name: glyphblt.asm
;
; Output a glyph onto VGA screen
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;

        .386

ifndef  DOS_PLATFORM
        .model  small,c
else
ifdef   STD_CALL
        .model  small,c
else
        .model  small,pascal
endif;  STD_CALL
endif;  DOS_PLATFORM

        assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        assume fs:nothing,gs:nothing

        .xlist
        include stdcall.inc             ;calling convention cmacros
        include i386\egavga.inc
        include i386\strucs.inc
        .list

        include i386\strblt.inc

        .code

;---------------------------Public-Routine------------------------------;
; vGlyphBlt
;
;   Draw a glyph to the VGA screen
;
;-----------------------------------------------------------------------;

_TEXT$01   SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

ProcName    xxxvGlyphBlt,vGlyphBlt,32

xxxvGlyphBlt proc uses    esi edi ebx,  \
        pdsurf: ptr DEVSURF,            \
        prcl:   ptr RECTL,              \
        cStr:   DWORD,                  \
        pgp:    ptr GLYPHPOS,           \
        iForeClr: dword,                \
        iBackClr: dword,                \
        ulMode:   dword,                \
        flOption: dword

        local   pjScreen    :ptr        ; screen pointer
        local   pjGlyph     :ptr        ; pointer to glyph bits
        local   cScan       :dword      ; visible glyph height
        local   cPels       :dword      ; visible glyph width
        local   cjBytes     :dword      ; glyph scan size
        local   cTmp        :dword      ; temporary scan count
        local   cInnerBytes :dword
        local   ulNextScan  :dword      ;offset from one screen scan to next
        local   cfBits      :byte
        local   cfLeft      :byte
        local   fjMask      :byte
        local   fjLastMask  :byte
        local   cfLastBits  :byte

; Initialize stuff

        cld
        mov     edi,pdsurf
        mov     esi,prcl

; Set the offset from one scan to the next

        mov     eax,[edi].dsurf_lNextScan
        mov     ulNextScan,eax

; Calculate number of scans for bltting cell

gblt_calc_dest_addr:
        mov     eax,[esi].yTop
        mov     edx,[esi].yBottom
        sub     edx,eax
        mov     cScan,edx               ; Number of scans

; Can we assume positive value?

        mov     edx,ulNextScan
        mul     edx                     ; EAX = byte offset to scan

; Calculate cell width in pels

        mov     ebx,[esi].xRight
        mov     ecx,[esi].xLeft
        sub     ebx,ecx
        mov     cPels,ebx               ; Width in pels

; Calculate pointer to the 1st screen byte to blt

        mov     edx,ecx
        shr     edx,3
        add     eax,edx
        add     eax,[edi].dsurf_pvBitmapStart
        mov     pjScreen,eax            ; Base address of blit

; Calculate the destination left edge mask

gblt_left_mask:
        xor     eax,eax
        cdq
        mov     cInnerBytes,eax         ; Assume glyph fits one byte
        mov     fjLastMask,al
        and     cl,7
        mov     dl,8
        sub     dl,cl                   ; DL = bits in mask

        dec     al
        shr     al,cl                   ; AL = left mask

; Assume cell is at least one byte wide

        mov     fjMask,al               ; then we have this left mask
        mov     cfBits,dl               ; along with 1 bits count
        sub     ebx,edx                 ; EBX = cPels, EDX = bits in left mask
        jg      short gblt_inner_count  ; but if the assume is true?
        je      short gblt_glyph_info

; It is less than one byte wide, calculate the right edge mask

        mov     cl,bl
        neg     cl
        inc     ah                      ; AH = 1
        shl     ah,cl
        neg     ah                      ; AH = right mask
        and     al,ah                   ; AL = composite mask
        mov     fjMask,al
        jmp     short gblt_glyph_info   ; no middle or last bytes

; Calculate the inner count

gblt_inner_count:
        mov     ecx,ebx                 ; EBX = # bits left in cell
        shr     ebx,3
        mov     cInnerBytes,ebx         ; inner byte count

; Calculate the last byte mask

gblt_last_mask:
        and     cl,7                    ; CL = # of trailing bits
        mov     cfLastBits,cl
        dec     ah                      ; AH = 0FFh
        shr     ah,cl
        not     ah
        mov     fjLastMask,ah

; Now get the glyph information

gblt_glyph_info:
        mov     edi,pgp
        mov     ebx,[edi].gp_pgdf
        mov     ebx,[ebx].gdf_pgb       ; ptr to glyph bits

; Calculate the glyph scan size

gblt_glyph_scan:
        mov     eax,[ebx].gb_cx         ; Glyph width in pels
        add     eax,7
;        and     al,0e0h                 ; DWORD aligned
        shr     eax,3
        mov     cjBytes,eax             ; Count to move to next line of glyph

; Assume the glyph is not clipped

        lea     edx,[ebx].gb_aj
        mov     pjGlyph,edx             ; Start of glyph
        mov     dl,8
        mov     cfLeft,dl               ; Bits left in glyph byte
        test    flOption,VGB_VERT_CLIPPED_GLYPH or VGB_HORIZ_CLIPPED_GLYPH
        jz      short gblt_draw_glyph

; Calculate byte offset of the 1st scan in glyph

gblt_glyph_offset:
        mov     edx,[esi].yTop
        sub     edx,[edi].gp_y          ; Vertical offset into glyph
        mul     edx                     ; Can we assume positive value?

; Calculate offset to the 1st byte in Glyph

        mov     edx,[esi].xLeft
        sub     edx,[edi].gp_x          ; Horizontal offset into glyph
        mov     ecx,edx
        shr     edx,3
        add     eax,edx                 ; Offset into glyph
        add     pjGlyph,eax             ; Start of glyph

; Calculate glyph's left mask

gblt_glyph_left_mask:
        and     cl,7
        sub     cfLeft,cl               ; Bits left in glyph byte

; Setup the drawing parameters

gblt_draw_glyph:
        mov     eax,ulMode              ; determine the write mode
        call    offset FLAT:vgblt_table.[eax*4]

; Everything is done, go home

glyph_blt_exit:

        cRet    vGlyphBlt

vgblt_table     equ     this dword
        dd      offset FLAT:vgblt_mix_glyph
        dd      offset FLAT:vgblt_opaque_glyph

        .errnz  VGB_MIX_STRING
        .errnz  VGB_OPAQUE_STRING-1

;---------------------------Public-Routine------------------------------;
; vgblt_mix_glyph
;
;   Draw a glyph to the VGA screen using the write mode 0
;
;-----------------------------------------------------------------------;

vgblt_mix_glyph::

        mov     dx,VGA_BASE + GRAF_ADDR ; Leave this in a register
        mov     eax,cScan
        mov     cTmp,eax                ; Scans to draw
        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        mov     bh,fjMask               ; Current mask
        mov     cl,cfLeft               ; Bits available in current byte

        sub     cl,cfBits
        jl      short vmg_fetch_two_bytes

;
; Fetching one byte means we are at the left edge of the glyph, or
; by some miracle we are aligned with the VGA memory.  Either way
; we will still mask the data with fjMask.
;

vmg_fetch_one_byte:
        mov     al,GRAF_BIT_MASK        ; leave it in AL

vmg_fetch_one_byte_next:
        mov     ah,[esi]                ; AH = glyph data

        shr     ah,cl                   ; Put usable glyph data in place

        and     ah,bh                   ; AH = masked glyph data
        jz      short @F                ; Don't waste time

        out     dx,ax
        xchg    ah,[edi]                ; Set the bits

@@:
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vmg_fetch_one_byte_next ; finish column

        neg     cl
        and     cl,7                    ; CL = # usable bits in next byte
        jnz     short vmg_advance_screen_ptr
        jmp     short vmg_advance_glyph_ptr

; The current screen byte covers two glyph bytes

vmg_fetch_two_bytes:
        mov     bl,GRAF_BIT_MASK        ; Set bitmask for altered bits
        neg     cl                      ; CL = # bits required from next byte
        add     cl,8                    ; we will have to swap AH and AL

vmg_fetch_two_bytes_next:
        mov     ax,[esi]                ; AL = current byte, AH = next byte
        rol     ax,cl                   ; AH = glyph data

        and     ah,bh                   ; AH = masked glyph data
        jz      short @F                ; Don't waste time

        mov     al,bl
        out     dx,ax
        xchg    al,[edi]                ; Set the bits

@@:
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vmg_fetch_two_bytes_next ; finish column
        sub     cl,8                    ; CL = # bits required from next byte

; We will start the next screen column byte. Recalculate parameters.

vmg_advance_glyph_ptr:
        inc     pjGlyph                 ; increment glyph pointer

vmg_advance_screen_ptr:
        inc     pjScreen                ; Increment screen pointer

vmg_inner_bytes:
        mov     ebx,cInnerBytes         ; do we have inner bytes?
        or      ebx,ebx
        jz      short vmg_last_byte

        mov     eax,cScan
        mov     cTmp,eax                ; Scans to draw
        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        add     pjGlyph,ebx             ; advance pointer
        add     pjScreen,ebx
        sub     cjBytes,ebx             ; glyph scan incremental
        or      cl,cl
        jnz     short vmg_inner_fetch_two_bytes

        mov     al,GRAF_BIT_MASK        ; leave it in AL

vmg_inner_fetch_one_byte:
        mov     ah,[esi]                ; AH = glyph data
        or      ah,ah
        jz      short @F                ; Don't waste time

        out     dx,ax
        xchg    ah,[edi]                ; Set the bits

@@:
        inc     esi
        inc     edi
        dec     ebx
        jnz     short vmg_inner_fetch_one_byte

        mov     ebx,cInnerBytes
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        sub     edi,ebx                 ; adjust for previous increment
        dec     cTmp
        jnz     short vmg_inner_fetch_one_byte ; finish column

        jmp     short vmg_inner_byte_end

; The current screen byte covers two glyph bytes

vmg_inner_fetch_two_bytes:
        add     cl,8                    ; we will have to swap AH and AL

vmg_inner_fetch_two_bytes_next:
        mov     ax,[esi]                ; AL = curr byte, AH = next byte
        rol     ax,cl                   ; AH = glyph data
        jz      short @F                ; Don't waste time

        mov     al,GRAF_BIT_MASK
        out     dx,ax
        xchg    al,[edi]                ; Set the bits
@@:
        inc     esi
        inc     edi
        dec     ebx
        jnz     short vmg_inner_fetch_two_bytes_next

        mov     ebx,cInnerBytes
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        sub     edi,ebx                 ; adjust for previous increment
        dec     cTmp
        jnz     short vmg_inner_fetch_two_bytes_next ; finish column
        sub     cl,8

vmg_inner_byte_end:
        add     cjBytes,ebx             ; restore its actual value

vmg_last_byte:
        mov     bl,fjLastMask           ; BL = last byte mask
        or      bl,bl
        jz      short vmg_exit

        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        mov     ch,8
        sub     ch,cl                   ; CH = # usable bits in current byte
        cmp     ch,cfLastBits           ; do we need the next byte?
        jl      short vmg_last_fetch_two_bytes

        mov     al,GRAF_BIT_MASK

vmg_last_fetch_one_byte:
        mov     ah,[esi]                ; AH = glyph data
        shl     ah,cl
        and     ah,bl
        jz      short @F                ; Don't waste time

        out     dx,ax
        xchg    ah,[edi]                ; Set the bits

@@:
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cScan
        jnz     short vmg_last_fetch_one_byte ; finish column

        jmp     short vmg_exit

; The current screen byte covers two glyph bytes

vmg_last_fetch_two_bytes:
        add     cl,8                    ; we will swap AH and AL
        mov     bh,GRAF_BIT_MASK

vmg_last_fetch_two_bytes_next:
        mov     ax,[esi]
        rol     ax,cl                   ; AH = glyph data
        and     ah,bl
        jz      short @F                ; Don't waste time

        mov     al,bh
        out     dx,ax
        xchg    al,[edi]                ; Set the bits

@@:
        add     edi,ulNextScan          ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cScan
        jnz     short vmg_last_fetch_two_bytes_next ; finish column

vmg_exit:
        retn

;---------------------------Public-Routine------------------------------;
; vgblt_opaque_glyph
;
;   Draw a glyph to the VGA screen using the write mode 3
;
;-----------------------------------------------------------------------;

vgblt_opaque_glyph:

        mov     eax,cScan
        mov     cTmp,eax                ; Scans to draw
        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        mov     bh,fjMask               ; Current mask
        mov     edx,ulNextScan

        mov     cl,cfLeft               ; Bits available in current byte
        sub     cl,cfBits
        jl      short vog_fetch_two_bytes

;
; Fetching one byte means we are at the left edge of the glyph, or
; by some miracle we are aligned with the VGA memory.  Either way
; we will still mask the data with fjMask.
;

vog_fetch_one_byte:
        mov     ah,[esi]                ; AH = glyph data
        shr     ah,cl                   ; Put usable glyph data in place
        and     ah,bh
        jz      short @F                ; don't waste time
        xchg    ah,[edi]                ; Set the bits
@@:
        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vog_fetch_one_byte ; finish column

        neg     cl
        and     cl,7                    ; CL = # usable bits in next byte
        jnz     short vog_advance_screen_ptr
        jmp     short vog_advance_glyph_ptr

; The current screen byte covers two glyph bytes

vog_fetch_two_bytes:
        neg     cl                      ; CL = cfBits - cfLeft
        add     cl,8                    ; we will swap AH and AL

vog_fetch_two_bytes_next:
        mov     ax,[esi]                ; AL = curr byte, AH = next byte
        rol     ax,cl                   ; AH = glyph data
        and     ah,bh
        jz      short @F                ; don't waste time
        xchg    ah,[edi]                ; Set the bits
@@:
        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vog_fetch_two_bytes_next ; finish column
        sub     cl,8

; We will start the next screen column byte. Recalculate parameters.

vog_advance_glyph_ptr:
        inc     pjGlyph

vog_advance_screen_ptr:
        inc     pjScreen                ; Increment screen pointer

vog_inner_bytes:
        mov     ebx,cInnerBytes         ; do we have inner bytes?
        or      ebx,ebx
        jz      short vog_last_byte

        mov     eax,cScan
        mov     cTmp,eax                ; Scans to draw
        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        add     pjGlyph,ebx             ; advance pointer
        add     pjScreen,ebx
        sub     cjBytes,ebx             ; glyph scan size
        sub     edx,ebx                 ; screen scan size
        or      cl,cl
        jnz     short vog_inner_fetch_two_bytes

vog_inner_fetch_one_byte:
        mov     ecx,ebx

vog_inner_loop:
        lodsb
        or      al,al
        jz      short @F
        xchg    al,[edi]
@@:
        inc     edi
        loop    short vog_inner_loop

        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vog_inner_fetch_one_byte ; finish column

        jmp     short vog_inner_byte_end

; The current screen byte covers two glyph bytes

vog_inner_fetch_two_bytes:
        add     cl,8

vog_inner_fetch_two_bytes_next:
        mov     ax,[esi]                ; AL = curr byte, AH = next byte
        rol     ax,cl                   ; AH = glyph data
        or      ah,ah
        jz      short @F
        xchg    ah,[edi]                ; Set the bits
@@:
        inc     esi
        inc     edi
        dec     ebx
        jnz     short vog_inner_fetch_two_bytes_next

        mov     ebx,cInnerBytes
        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cTmp
        jnz     short vog_inner_fetch_two_bytes_next ; finish column
        sub     cl,8

vog_inner_byte_end:
        add     edx,ebx                 ; restore its original value
        add     cjBytes,ebx             ; restore its original value

vog_last_byte:
        mov     bl,fjLastMask           ; BL = last byte mask
        or      bl,bl
        jz      short vog_exit

        mov     esi,pjGlyph             ; Read glyph from here
        mov     edi,pjScreen            ; Write glyph to there
        mov     ch,8
        sub     ch,cl                   ; CH = # usable bits in current byte
        cmp     ch,cfLastBits           ; do we need the next byte?
        jl      short vog_last_fetch_two_bytes


vog_last_fetch_one_byte:
        mov     ah,[esi]                ; AH = glyph data
        shl     ah,cl
        and     ah,bl
        jz      short @F
        xchg    ah,[edi]                ; Set the bits
@@:
        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cScan
        jnz     short vog_last_fetch_one_byte ; finish column

        jmp     short vog_exit

; The current screen byte covers two glyph bytes

vog_last_fetch_two_bytes:
        add     cl,8                    ; we will swap AH and AL

vog_last_fetch_two_bytes_next:
        mov     ax,[esi]
        rol     ax,cl                   ; AH = glyph data
        and     ah,bl
        jz      short @F
        xchg    ah,[edi]                ; Set the bits
@@:
        add     edi,edx                 ; Next scan on VGA
        add     esi,cjBytes             ; Next line of glyph
        dec     cScan
        jnz     short vog_last_fetch_two_bytes_next ; finish column

vog_exit:
        retn

xxxvGlyphBlt endp


;---------------------------Public-Routine------------------------------;
; ulSetXParentRegs
;
;   Set the VGA control registers for the specified Rop4 and foreground
;   color when background is transparent.
;
;-----------------------------------------------------------------------;

cProc   ulSetXParentRegs,12,<           \
        uses    ebx edi,                \
        rop4:   dword,                  \
        pclr:   ptr,                    \
        bSet:   dword                   >

        mov     edi,VGB_OPAQUE_STRING
        mov     ebx,rop4
        xor     ecx,ecx                 ; Color = 00, mode = set
        or      ebx,ebx
        jz      short vsv_set_vga_mode

        dec     ch                      ; Color = FF, mode = set
        inc     bx
        jz      short vsv_set_vga_mode

        mov     eax,pclr
        mov     ch,byte ptr [eax]       ; Color = passed color, mode = set
        cmp     bx,0f0f0h + 1
        je      short vsv_set_vga_mode

        not     ch                      ; ~passed color
        cmp     bx,00f0fh + 1
        je      short vsv_set_vga_mode

        mov     cx,0FF00h + DR_XOR      ; Color = FF, mode = xor
        mov     edi,VGB_MIX_STRING      ; We will actually do mode 0

vsv_set_vga_mode:
        mov     eax,bSet                ; set flag
        or      eax,eax
        jz      short vsv_exit

        mov     dx,VGA_BASE + GRAF_ADDR
        mov     al,GRAF_SET_RESET
        mov     ah,ch
        out     dx,ax
        mov     ax,0f00h + GRAF_ENAB_SR
        out     dx,ax
        mov     ah,cl
        mov     al,GRAF_DATA_ROT
        out     dx,ax

        or      edi,edi
        .errnz  VGB_MIX_STRING
        jz      short vsv_exit
        mov     ax,(M_AND_WRITE shl 8)+GRAF_MODE
        out     dx,ax

vsv_exit:
        mov     eax,edi                 ; return VGA mode
        mov     edi,pclr
        mov     byte ptr [edi],ch       ; CH = actual foreground color
        cRet    ulSetXParentRegs

endProc ulSetXParentRegs

;---------------------------Public-Routine------------------------------;
; vResetVGARegs
;
;   Reset the VGA control registers to a default state.
;
;-----------------------------------------------------------------------;

cProc   vResetVGARegs

        mov     dx,VGA_BASE + GRAF_ADDR
        mov     ax,0ff00h + GRAF_BIT_MASK
        out     dx,ax
        mov     ax,0000h + GRAF_SET_RESET
        out     dx,ax
        mov     ax,0000h + GRAF_ENAB_SR
        out     dx,ax
        mov     ax,(DR_SET shl 8) + GRAF_DATA_ROT
        out     dx,ax
        mov     ax,((M_PROC_WRITE or M_DATA_READ) shl 8) + GRAF_MODE
        out     dx,ax

        cRet    vResetVGARegs

endProc vResetVGARegs

public gblt_calc_dest_addr
public gblt_left_mask
public gblt_inner_count
public gblt_last_mask
public gblt_glyph_info
public gblt_glyph_offset
public gblt_draw_glyph
public glyph_blt_exit
public vgblt_mix_glyph
public vmg_fetch_one_byte
public vmg_fetch_two_bytes
public vmg_advance_glyph_ptr
public vmg_advance_screen_ptr
public vmg_inner_bytes
public vmg_inner_fetch_one_byte
public vmg_inner_fetch_two_bytes
public vmg_last_byte
public vmg_last_fetch_one_byte
public vmg_last_fetch_two_bytes
public vmg_exit
public vgblt_opaque_glyph
public vog_fetch_one_byte
public vog_fetch_two_bytes
public vog_advance_glyph_ptr
public vog_advance_screen_ptr
public vog_inner_bytes
public vog_inner_fetch_one_byte
public vog_inner_fetch_two_bytes
public vog_last_byte
public vog_last_fetch_one_byte
public vog_last_fetch_two_bytes
public vog_exit

_TEXT$01   ends

        end


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.