Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;/****************************************************************************
- ;*
- ;* Low-level Video I/O module for Windowing environment
- ;*
- ;* Copyright (C) 1993-1994 Emory Horvath
- ;* All rights reserved.
- ;*
- ;****************************************************************************/
- MOUSE_SUPPORT EQU 1
- IFDEF DEBUG
- MONO_2 EQU 1
- ENDIF
- .286
- .MODEL small, pascal
- CR EQU 13
- LF EQU 10
- TAB EQU 9
- SPACE EQU 32
- MDA EQU 0 ; Adapter constants
- CGA EQU 1
- MCGA EQU 2
- EGA EQU 3
- VGA EQU 4
- MONO EQU 0 ; Display constants
- COLOR EQU 1
- ;;
- ;; Structure for video configuration
- ;;
- VIDINFO STRUCT
- sgmnt WORD ?
- curStd WORD ?
- curInsert WORD ?
- curOverwrite WORD ?
- mode BYTE ?
- dpage BYTE ?
- rows BYTE ?
- cols BYTE ?
- display BYTE ?
- adapter BYTE ?
- primary BYTE ?
- secondary BYTE ?
- fShowCursor BYTE ?
- VIDINFO ENDS
- ;;
- ;; Structure for storing startup video info, for restoring upon exit
- ;;
- OLDINFO STRUCT
- cursor WORD ?
- sgmnt WORD ?
- mode BYTE ?
- dpage BYTE ?
- rows BYTE ?
- xCur BYTE ?
- yCur BYTE ?
- OLDINFO ENDS
- RECT STRUCT
- left WORD ?
- top WORD ?
- right WORD ?
- bottom WORD ?
- RECT ENDS
- POINT STRUCT
- x WORD ?
- y WORD ?
- POINT ENDS
- ;;
- ;; BLOCK - Header structure for saved screen regions
- ;;
- BLOCK STRUCT
- voffset WORD ?
- ccols WORD ?
- clines WORD ?
- BLOCK ENDS
- IFDEF MOUSE_SUPPORT
- EXTERN PASCAL MouseShow:PROC
- EXTERN PASCAL MouseHide:PROC
- ENDIF
- IFDEF DEBUG
- EXTERN PASCAL DbgOut:PROC
- ENDIF
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- .DATA
- vinfo VIDINFO <>
- PUBLIC vinfo
- oinfo OLDINFO <>
- PUBLIC oinfo
- attr BYTE 07h ; Current cell attributes
- IFDEF MONO_2
- ;; Info for secondary mono debug monitor, if present
- ;;
- mseg WORD 0 ; Saved vid buffer seg of primary
- mattr BYTE ? ; Saved attr for primary
- mdisplay BYTE ? ; Saved primary display type
- mrows BYTE ? ; Saved # of rows
- mcols BYTE ? ; Saved # of cols
- sseg WORD ? ; Vid buffer seg of secondary
- sattr BYTE 07h ; Attr to use for secondary
- sdisplay BYTE ? ; Secondary type (MONO, COLOR)
- srows BYTE ? ; Secondary monitor rows
- scols BYTE ? ; Secondary monitor cols
- ENDIF
- IFDEF MOUSE_SUPPORT
- EXTERN cxMouse:WORD ; Current mouse x-coord (in MOUSE.ASM)
- EXTERN cyMouse:WORD ; Current mouse y-coord (in MOUSE.ASM)
- EXTERN fUpdateMouse:BYTE ; Cursor has been overwritten and
- ENDIF ; needs to be redisplayed.
- IFDEF DEBUG
- msgVid1 DB ' 10.1A passed', LF, 0
- msgVid2 DB ' Check EGA', LF, 0
- msgVid3 DB ' Check CGA', LF, 0
- ENDIF
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- .CODE
- IFDEF DEBUG
- ;/****************************************************************************
- ;* VidDbgOut() - Displays a debug message
- ;****************************************************************************/
- VidDbgOut PROC NEAR USES ax bx cx dx es, pszMsg:WORD
- pushf
- push pszMsg
- call DbgOut
- popf
- ret
- VidDbgOut ENDP
- ENDIF
- DebugOut MACRO msg
- IFDEF DEBUG
- push offset msg
- call VidDbgOut
- ENDIF
- ENDM
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; VideoBios() -
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- public VideoBios
- VideoBios::
- push bp
- int 10h
- pop bp
- ret
- ;/*****************************************************************************
- ;* VidInit() - Initializes video module
- ;*
- ;* Determines current mode and hardware, saves old mode, puts video in
- ;* known state, and clears screen.
- ;*
- ;* GetVidInfo() MUST be called before calling VidInit()!
- ;*
- ;* Params
- ;* cLines - #of lines to init screen to, or 0 if use current #lines
- ;* fHigh - TRUE to enable high-intensity background colors
- ;* Return
- ;* TRUE if successful, FALSE if error.
- ;*****************************************************************************/
- VidInit PROC cLines:WORD, fHigh:WORD
- ;; Save original screen state, to restore upon exit
- mov ax, vinfo.curStd
- mov oinfo.cursor, ax
- mov ax, vinfo.sgmnt
- mov oinfo.sgmnt, ax
- mov al, vinfo.dpage
- mov oinfo.dpage, al
- mov al, vinfo.rows
- mov oinfo.rows, al
- mov al, vinfo.mode
- mov oinfo.mode, al
- ;; Get original cursor position
- mov ax, 0300h
- mov bh, vinfo.dpage
- call VideoBios
- mov oinfo.xCur, dl
- mov oinfo.yCur, dh
- ;; Set to display page 0
- cmp vinfo.dpage, 0h
- je vi1
- mov ax, 0500h
- call VideoBios
- mov vinfo.dpage, 0h
- vi1:
- ;;
- ;; Are we in standard 80x25/43/50 mode? If not, then put us in it.
- ;; There be a lot of custom modes out there, and i'll have no idea how
- ;; to handle them (not to mention those graphics modes!).
- ;;
- cmp vinfo.mode, 02 ; 80x25/43/50 no burst ?
- je vi4
- cmp vinfo.mode, 03 ; 80x25/43/50 burst ?
- je vi4
- cmp vinfo.mode, 07 ; 80x25 monochrome ?
- je vi4
- mov ax, 0003h ; Switch to standard 80x25 mode
- call VideoBios
- call GetVidInfo ; Everything's changed now, so recheck
- ;; If previous mode had large # of lines, then try to switch to
- ;; 43/50 line mode here.
- cmp oinfo.rows, 40
- jl vi4
- push word ptr 50
- call VidSetLines
- jmp short vi2
- vi4:
- call VidClearScreen
- ;; Set new line mode, if caller requested it
- mov ax, cLines
- or ax, ax
- jz vi2
- cmp vinfo.mode, 07h ; Don't change if in mono-text mode
- je vi2
- push ax
- call VidSetLines
- ;; Set insert-mode cursor
- vi2:
- push word ptr 01h
- call VidSetCurType
- ;; Enable high-intensity background colors?
- cmp fHigh, 00h
- jz vi3
- xor ax, ax
- push ax
- call VidSetBlink
- vi3:
- mov ax, 1 ; Return success
- ret
- VidInit ENDP
- ;/*****************************************************************************
- ;* VidTerminate() - Closes down video library and restores startup state
- ;*
- ;* Params
- ;* None.
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidTerminate PROC
- ;; Reenable blinking
- push word ptr 01h
- call VidSetBlink
- ;; Does video mode need to be restored?
- ;;
- ;; My thinking here is that the standard 25/43/50 line EGA/VGA modes will
- ;; be restored correctly by VidSetLines(), and that the proprietary modes
- ;; will be using a different mode #, so they'll be restored correctly
- ;; by SetVideoMode below. We'll see how well this turns out...
- ;;
- mov al, oinfo.mode
- cmp al, vinfo.mode
- je vt3
- mov vinfo.mode, al
- xor ah, ah ; Set Video Mode
- call VideoBios
- jmp short vt1 ; And skip the restore-linemode step
- vt3:
- call VidClearScreen
- ;; Does linemode need to be restored?
- xor ax, ax
- mov al, oinfo.rows
- cmp al, vinfo.rows
- je vt1
- inc ax
- push ax
- call VidSetLines
- vt1:
- ;; Does page need to be restored?
- mov al, oinfo.dpage
- cmp al, vinfo.dpage
- je vt2
- mov ah, 05h
- call VideoBios
- vt2:
- ;; Restore cursor type
- mov cx, oinfo.cursor
- mov ax, 0100h
- call VideoBios
- ;; Set cursor to orginal position
- mov bh, oinfo.dpage
- mov dl, oinfo.xCur
- mov dh, oinfo.yCur
- mov ax, 0200h
- call VideoBios
- ret
- VidTerminate ENDP
- ;****************************************************************************
- ;* GetVidInfo - Determines current video configuration and initializes
- ;* the vconfig structure.
- ;*
- ;* Derived from QC251/MASM6 sample source
- ;*
- ;* Uses: vinfo
- ;*
- ;* Params: None
- ;*
- ;* Return: None
- ;****************************************************************************
- GetVidInfo PROC
- mov ax, 1A00h ; Get video info for VGA
- call VideoBios
- chkVGA:
- cmp al, 1Ah ; Is VGA or MCGA present?
- jne chkEGA ; No? Then check for EGA
- DebugOut msgVid1
- IFDEF MONO_2
- ;; Determine if secondary debug monitor. I allow only the following for now:
- ;; Primary=VGA with Secondary=MDA.
- ;; If anything else, they can't use debug monitor.
- ;;
- ;; BL = Active display type
- ;; BH = Inactive display type
- ;;
- mov sseg, 00h ; Assume no debug monitor
- cmp bh, 01h ; Secondary == MDA?
- jne gviNoDebug
- cmp bl, 07h ; Primary < Monochrome VGA?
- jl gviNoDebug
- cmp bl, 08h ; Primary > Color VGA?
- jg gviNoDebug
- mov sseg, 0B000h ; Set up secondary info
- mov sdisplay, MONO
- mov srows, 24
- mov scols, 80
- gviNoDebug:
- ENDIF
- cmp bl, 2 ; If VGA exists as secondary adapter,
- je isCGA ; check for CGA and mono as primary
- jb isMONO
- cmp bl, 5 ; If EGA is primary, do normal
- jbe chkEGA ; EGA checking
- chkMCGA:
- mov vinfo.adapter, MCGA ; Yes? Assume MCGA
- mov vinfo.display, COLOR
- cmp bl, 8 ; Correct assumption?
- ja gotmode ; Yes? Continue
- isVGA:
- mov vinfo.adapter, VGA ; Assume it's VGA color
- ;; ECH - Use color colors for VGA Mono as well (8514 reports as VGA Mono)
- ;; je gotmode ; Yes? Continue
- ;; mov vinfo.display, MONO ; No? Must be VGA mono
- jmp gotmode ; Finished with VGA, so jump
- chkEGA:
- DebugOut msgVid2
- mov ah, 12h ; Call EGA status function
- mov bl, 10h
- sub cx, cx ; Clear status bits
- call VideoBios
- ;;
- ;; ?BUGBUG? - _Interrupt_List_ says that you should call this function with
- ;; BH=FFh. If BH unchanged on return, then EGA not installed.
- ;;
- jcxz chkCGA ; If CX is unchanged, not EGA
- isEGA:
- mov vinfo.adapter, EGA ; Set structure fields for EGA
- mov vinfo.display, MONO ; Assume EGA mono
- or bh, bh ; Correct assumption?
- jnz gotmode ; Yes? Continue
- mov vinfo.display, COLOR ; No? Must be EGA color
- jmp gotmode ; Finished with EGA, so jump
- chkCGA:
- DebugOut msgVid3
- int 11h ; Get equipment list
- and al, 30h ; If bits 4-5 set, monochrome
- cmp al, 30h ; Monochrome text mode?
- je isMONO ; Yes? Continue
- isCGA:
- mov vinfo.adapter, CGA ; No? Must be CGA
- mov vinfo.display, COLOR
- jmp gotmode
- isMONO:
- mov vinfo.adapter, MDA ; Set MONO
- mov vinfo.display, MONO
- mov vinfo.sgmnt, 0B000h ; Monochrome (MDA) mode
- gotmode:
- mov ah, 0Fh
- call VideoBios ; Get current mode
- mov vinfo.mode, al ; Record mode
- mov vinfo.dpage, bh ; and current page
- ;; If mode 7, force to use monochrome
- cmp al, 7
- jne gviColor
- mov vinfo.display, MONO
- mov vinfo.sgmnt, 0B000h ; Monochrome (MDA) mode
- mov vinfo.curInsert, 0B0Ch
- mov vinfo.curOverwrite, 000Ch
- jmp short getdispl
- gviColor:
- mov vinfo.sgmnt, 0B800h ; Color mode
- mov vinfo.curInsert, 0607h
- mov vinfo.curOverwrite, 0007h
- getdispl:
- mov ax, 0040h
- mov es, ax
- mov al, es:[004Ah] ; Get number of display cols
- mov vinfo.cols, al ; Store in structure
- mov vinfo.rows, 24 ; Assume bottom row # = 24
- cmp vinfo.adapter, EGA ; EGA or VGA?
- jl gviCurs ; No? Exit
- mov ax, 1130h ; Yes? Request character info
- sub bh, bh ; Set BH to valid value
- call VideoBios ; Get number of rows/screen
- ;;
- ;; ?BUGBUG? - _Interrupt_List_ says that EGA returns (#of rows), rather than
- ;; (#of rows - 1). But INFOPLUS doesn't take this into account either.
- ;; MSD gets #of rows-1 from byte at 0040h:0084h.
- ;;
- mov vinfo.rows, dl ; Keep in structure
- gviCurs:
- ;; Get cursor info
- mov ax, 0300h
- mov bh, vinfo.dpage
- call VideoBios
- mov vinfo.curStd, cx
- ret
- GetVidInfo ENDP
- ;****************************************************************************
- ;* VidSetLines - Sets line mode for EGA or VGA.
- ;*
- ;* Derived from QC251/MASM6 sample source.
- ;*
- ;* Uses: vinfo - Video configuration structure (initialized
- ;* by calling the GetVidConfig procedure)
- ;*
- ;* Params: Line - Requested line mode (25, 43, or 50)
- ;*
- ;* Return: Short integer with error code
- ;* 0 if successful
- ;* 1 if error
- ;****************************************************************************
- VidSetLines PROC Line:WORD
- cmp vinfo.adapter, EGA
- jl slmE_exit
- ;;
- ;; Sets highest linemode possible that's <= Line
- ;;
- mov ax, Line
- cmp vinfo.adapter, EGA ; >25 lines only available on EGA/VGA
- jl line25
- cmp al, 25
- jle line25
- cmp al, 43
- jle line43
- jmp short line50
- line25:
- mov vinfo.rows, 24
- mov al, 11h ; Set for EGA 25-line mode
- cmp vinfo.adapter, EGA ; EGA?
- je linemode ; Yes? Continue
- mov ax, 1202h ; No? Function 12h for VGA
- mov bl, 30h ; AL = 2 for 400 scan lines
- call VideoBios ; Reset to 400 scan lines
- mov ax, 0003 ; Reset mode to enable new #scanlines
- call VideoBios
- mov al, 14h ; Request 8x16 char matrix
- jmp linemode
- line43:
- mov vinfo.rows, 42
- mov al, 12h ; Set for EGA 43-line mode
- cmp vinfo.adapter, EGA ; EGA?
- je linemode ; Yes? Continue
- mov ax, 1201h ; No? Function 12h for VGA
- mov bl, 30h ; AL = 1 for 350 scan lines
- call VideoBios ; Reset to 350 scan lines
- mov ax, 0003 ; Reset mode to enable new #scanlines
- call VideoBios
- mov al, 12h ; Request 8x8 character matrix
- jmp linemode
- line50:
- mov vinfo.rows, 49
- cmp vinfo.adapter, VGA ; VGA?
- jne line43 ; No? Try 43line mode instead
- mov ax, 1202h ; Yes? Function 12h
- mov bl, 30h ; AL = 2 for 400 scan lines
- call VideoBios ; Reset to 400 scan lines
- mov ax, 0003 ; Reset mode to enable new #scanlines
- call VideoBios
- mov al, 12h ; Request 8x8 character matrix
- linemode:
- sub bl, bl ; Use table 0
- mov ah, 11h ; Request Function 11h
- call VideoBios ; Set new line mode
- mov ah, 12h ; Select alternate print
- mov bl, 20h ; screen for EGA and VGA
- call VideoBios
- cmp vinfo.adapter, VGA ; VGA?
- je slmExit ; Yes? Then exit
- push word ptr 01h
- call VidSetCurType
- jmp slmExit ; Normal exit
- slmE_exit:
- mov ax, 1 ; Set error code
- jmp slmExit2
- slmExit:
- call VidClearScreen
- sub ax, ax ; Clear error code
- slmExit2:
- ret
- VidSetLines ENDP
- ;/*****************************************************************************
- ;* VidSetBlink() - Enables/Disables background blinking
- ;*
- ;* Params
- ;* fBlink - TRUE to enable blinking, FALSE to enable high-intensity
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidSetBlink PROC fBlink:WORD
- mov al, vinfo.adapter
- cmp al, CGA ; If <CGA, don't bother
- jl vsblExit1
- cmp al, MCGA ; If <MCGA, must set it manually
- jl vsblUsePort
- ;; For EGA and above, we can use Int 10h, Function 1003h.
- mov ax, 01003h
- xor bh, bh ; For Boca EGA (see _Interrupt_List_)
- mov bl, byte ptr fBlink
- call VideoBios
- jmp short vsblExit1
- ;; Oh well, got to do it manually...
- vsblUsePort:
- mov dx, 03D8h ; CGA's Mode-Control register
- ;;
- ;; My MDA card did some strange things once in awhile when i tried this.
- ;; MDA not important enough to bother with here anyway.
- ;;
- ;;;;
- ;;;; Well no wonder it did strange things - the previous code was using
- ;;;; random values in ES!
- ;;;;
- ; cmp al, CGA
- ; je vsblDoIt
- ; cmp al, MDA ; Not CGA, is it MDA?
- ; jne vsblExit1 ; Don't recognize the adapter
- ; mov dx, 03B8h ; MDA's Mode-Control register
- vsblDoIt:
- ;; Load current value of Mode-Control register from video data area
- mov ax, 040h ; Video-data segment
- mov es, ax
- mov bx, 065h ; Mode-Control reg contents address
- mov al, es:[bx]
- ;; Do we set it or clear it?
- cmp byte ptr fBlink, 00h
- jnz vsblSetIt
- and al, 11011111b ; Clear blink-enable bit
- jmp short vsblWrite
- vsblSetIt:
- or al, 00100000b ; Set blink-enable bit
- ;; Ok, write it out now
- vsblWrite:
- mov es:[bx], al ; Save changes back to vid-data area
- out dx, al ; And set the Mode-Control register
- vsblExit1:
- ret
- VidSetBlink ENDP
- ;****************************************************************************
- ;* VidClearScreen() - Clears entire screen to white-on-black
- ;*
- ;* Params
- ;* None.
- ;* Returns
- ;* None.
- ;****************************************************************************
- VidClearScreen PROC
- LOCAL r:RECT
- xor ax, ax ; Set up rect to include entire screen
- mov r.top, ax
- mov r.left, ax
- mov al, vinfo.cols
- mov r.right, ax
- mov al, vinfo.rows
- inc al
- mov r.bottom, ax
- lea ax, r.left
- push ax
- mov ah, 07h ; assume white on black for now
- mov attr, ah
- mov al, SPACE
- push ax
- call VidFillBlock
- ret
- VidClearScreen ENDP
- IFDEF MONO_2
- ;/*****************************************************************************
- ;* VidHasDebug() - Returns TRUE if system has secondary debug monitor.
- ;* Currently only recognizes Primary=VGA with Secondary=MDA.
- ;*
- ;* Params
- ;* None.
- ;* Return
- ;* TRUE if debug monitor present, FALSE if not.
- ;*****************************************************************************/
- VidHasDebug PROC
- xor ax, ax
- ;; Do we have a debug monitor?
- cmp sseg, 0h
- jz vhdExit1
- mov al, 01h
- vhdExit1:
- ret
- VidHasDebug ENDP
- ENDIF
- IFDEF MONO_2
- ;/*****************************************************************************
- ;* VidUseDebug() - Switches to secondary debug monitor.
- ;*
- ;* Params
- ;* None.
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidUseDebug PROC
- ;; Do we have a debug monitor?
- cmp sseg, 0h
- jz vudErr1
- ;; Are we already using debug?
- cmp mseg, 0h
- jnz vudErr1
- ;; Save primary info
- mov ax, vinfo.sgmnt
- mov mseg, ax
- mov al, vinfo.display
- mov mdisplay, al
- mov al, attr
- mov mattr, al
- mov al, vinfo.rows
- mov ah, vinfo.cols
- mov mrows, al
- mov mcols, ah
- ;; Reintialize with debug info
- mov ax, sseg
- mov vinfo.sgmnt, ax
- mov al, sdisplay
- mov vinfo.display, al
- mov al, sattr
- mov attr, al
- mov al, srows
- mov ah, scols
- mov vinfo.rows, al
- mov vinfo.cols, ah
- vudErr1:
- ret
- VidUseDebug ENDP
- ENDIF
- IFDEF MONO_2
- ;/*****************************************************************************
- ;* VidUseMain() - Switches back to primary monitor.
- ;*
- ;* Params
- ;* None.
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidUseMain PROC
- ;; Are we already using main?
- cmp mseg, 0h
- jz vumErr1
- ;; Save debug info
- mov al, attr
- mov sattr, al
- ;; Reintialize with primary info
- mov ax, mseg
- mov vinfo.sgmnt, ax
- mov mseg, 0h ; Record that we're now in 'main' mode
- mov al, mdisplay
- mov vinfo.display, al
- mov al, mattr
- mov attr, al
- mov al, mrows
- mov ah, mcols
- mov vinfo.rows, al
- mov vinfo.cols, ah
- vumErr1:
- ret
- VidUseMain ENDP
- ENDIF
- IFDEF MONO_2
- ;/*****************************************************************************
- ;* MDAShowCursor() - Shows/hides the cursor on MDA, bypassing BIOS.
- ;*
- ;* Params
- ;* AX: TRUE if show cursor, FALSE if hide
- ;* Return
- ;* None.
- ;* Uses
- ;* AX, CD DX
- ;*****************************************************************************/
- MDAShowCursor PROC
- ;;
- ;; I can't use the bios to set cursor on debug monitor, since primary
- ;; monitor is currently active (changing video mode to monochrome didn't
- ;; work at all). So i've got to write directly to the CRT registers.
- ;;
- ;; Show or Hide cursor?
- mov cx, 2000h ; Assume hide-cursor
- or ax, ax
- mov ax, 0B0Ah ; Cursor end-line/start-line registers
- jz mdaWriteIt
- mov cx, 0B0Ch ; Else set normal cursor
- jmp short mdaWriteIt
- MDAShowCursor ENDP
- ENDIF
- IFDEF MONO_2
- ;/*****************************************************************************
- ;* MDASetCurPos() - Sets cursor position on MDA, bypassing BIOS
- ;*
- ;* Params
- ;* AX: Y coordinate
- ;* DX: X coordinate
- ;* Return
- ;* None.
- ;* Uses
- ;* AX, CX, DX
- ;*****************************************************************************/
- MDASetCurPos PROC
- ;;
- ;; I can't use the bios to set cursor on debug monitor, since primary
- ;; monitor is currently active (changing video mode to monochrome didn't
- ;; work at all). So i've got to write directly to the CRT registers.
- ;;
- ;; Calculate new cursor offset
- mov cl, 80
- mul cl
- add ax, dx
- mov cx, ax ; And save it in CX
- mov ax, 0F0Eh ; Cursor-location low/high register
- mdaWriteIt::
- ;; Write high-byte of new cursor offset
- mov dx, 03B4h ; CRT Index Register for MDA
- out dx, al
- inc dx ; Output port is at 3B5h
- mov al, ch ; Write high-byte of offset
- out dx, al
- dec dx
- ;; Write low-byte of new cursor offset
- mov al, ah
- out dx, al
- inc dx ; Output port is at 3B5h
- mov al, cl ; Write low-byte of offset
- out dx, al
- ret
- MDASetCurPos ENDP
- ENDIF
- ;/*****************************************************************************
- ;* Internal function. Calculates offset to write to in video segment, and
- ;* determines whether mouse cursor will be overwritten.
- ;*
- ;* Params
- ;* AX : Line to move to (0-based, and cliprect-relative)
- ;* DX : Column to move to (0-based, and cliprect-relative)
- ;* CX : # of chars requested to write
- ;* Return
- ;* BX : Offset into video buffer
- ;* CX : # of chars to write (clipped to current cliprect)
- ;* Carry : Clear if char visible, Set if not.
- ;* Registers Destroyed
- ;* AX, BX, CX, DX, Flags
- ;*
- ;*****************************************************************************/
- CalcXYC:
- ; If 0 chars to write, then abort now. The writestring routines have
- ; problems with 0-length strings. So DON'T remove this check!
- ; Also, a 0-length string is NOT an error.
- or cx, cx
- jz cxyErr1
- IFDEF MOUSE_SUPPORT
- ; Determine whether mouse cursor might be overwritten
- cmp ax, cyMouse ; Check if on same line
- jne cxyCalc
- cmp dx, cxMouse ; Check if after starting column
- jg cxyCalc
- mov bx, dx ; Check if before ending column.
- add bx, cx
- cmp bx, cxMouse
- jle cxyCalc
- push ax
- push cx
- push dx
- call MouseHide
- pop dx
- pop cx
- pop ax
- mov BYTE PTR fUpdateMouse, 01h ; It might be overwritten
- ENDIF
- ; Now calculate offset
- ; Line# is already in AX
- cxyCalc:
- mul BYTE PTR vinfo.cols ; Calculate start of line
- add ax, dx
- shl ax, 1 ; Change units from bytes to chars
- mov bx, ax ; Return address in BX
- cxyExit:
- clc
- ret
- cxyErr1:
- stc
- ret
- ;/*****************************************************************************
- ;* VidWrtChar() -- Write character to screen, in current cliprect
- ;*
- ;* Notes
- ;* Doesn't handle special chars. This is the responsibility of
- ;* other modules.
- ;* Params
- ;* ry - y-coord (0-based)
- ;* rx - x-coord (0-based)
- ;* char - char to write
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidWrtChar PROC ry:WORD, rx:WORD, char:BYTE
- mov ax, ry
- mov dx, rx
- mov cx, 01h ; Tell CalcXy() we're writing one char
- call CalcXYC ; Calculate video address to write to
- ; returns offset in BX
- mov es, vinfo.sgmnt ; Load video segment
- mov al, char ; Load char
- mov ah, attr ; Load char attributes
- mov es:[bx], ax ; Write the char!
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vwcEnd
- call MouseShow
- ENDIF
- ;; Exit sequence
- vwcEnd:
- ret
- VidWrtChar ENDP
- ;/*****************************************************************************
- ;* VidWrtStr() -- Writes a string to screen
- ;*
- ;* Notes
- ;* Doesn't handle special chars. This is the responsibility of
- ;* other modules.
- ;* Params
- ;* RY ry - y-coord
- ;* RX rx - x-coord
- ;* LPSTR lpsz - far ptr to string
- ;* uint cChars - #of chars to write
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidWrtStr PROC USES si, ry:WORD, rx:WORD, lpsz:DWORD, cChars:WORD
- ;;
- ;; DS:SI - Address of current char in supplied string
- ;; ES:BX - Address to write current char to
- ;; CX - Number of chars left to write (adjusted for cliprect)
- ;; AL - Current char to write
- ;; AH - Attributes to use
- ;;
- mov ax, ry
- mov dx, rx
- mov cx, cChars
- call CalcXYC ; Calculate video address to write to
- ; returns offset in BX, and #of chars to write in CX
- jc vwsEnd ; Not visible!
- ; BX has starting offset
- ; CX has # of chars to write
- mov es, vinfo.sgmnt ; Load video segment
- mov ah, attr ; Load current display attribute
- push ds
- lds si, lpsz ; Load string to display
- even
- vwsLoop:
- mov al, ds:[si] ; read current char
- mov es:[bx], ax ; write curent char
- inc si ; goto next char
- add bx, 2 ; goto next video cell
- dec cx ; decrement chars-left-to-write counter
- jnz vwsLoop ; loop again if more chars to write
- pop ds
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vwsEnd
- call MouseShow
- ENDIF
- vwsEnd:
- ret
- VidWrtStr ENDP
- IFNDEF QEDIT
- ;/*****************************************************************************
- ;* VidWrtCells() -- Writes string/attributes to screen
- ;*
- ;* Notes
- ;* Doesn't handle special chars. This is the responsibility of
- ;* other modules.
- ;* Params
- ;* RY ry
- ;* RX rx
- ;* LPSTR lpCells
- ;* uint cCells : # of cells, not # of chars
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidWrtCells PROC USES ds si di, ry:WORD, rx:WORD, lpCells:DWORD, cCells:WORD
- ;;
- ;; DS:SI - Address of current char in supplied string
- ;; ES:BX - Address to write current char to
- ;; CX - Number of chars left to write (adjusted for cliprect)
- ;; AL - Current char to write
- ;; AH - Attributes to use
- ;;
- mov ax, ry
- mov dx, rx
- mov cx, cCells
- call CalcXYC ; Calculate video address to write to
- ; returns offset in BX, and #of chars to write in CX
- jc vwclEnd ; Not visible!
- mov di, bx
- ; BX has starting offset
- ; CX has # of chars to write
- mov es, vinfo.sgmnt ; Load video segment
- lds si, lpCells ; Load string to display
- cld
- rep movsw ; Write the chars
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vwclEnd
- call MouseShow
- ENDIF
- vwclEnd:
- ret
- VidWrtCells ENDP
- ENDIF
- ;/*****************************************************************************
- ;* VidWrtCharN() - Writes char to screen N times
- ;*
- ;* Params
- ;* RY ry : row
- ;* RX rx : column
- ;* CHAR char : char to write
- ;* uint cChars : #of chars to write
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidWrtCharN PROC USES di, ry:WORD, rx:WORD, char:BYTE, cChars:WORD
- mov ax, ry
- mov dx, rx
- mov cx, cChars
- call CalcXYC ; Calculate video address to write to
- ; returns offset in BX, and #of chars to write in CX
- jc vwnEnd ; Not visible!
- mov di, bx
- ;; CX has # of chars to write
- ;; DI has offset in video buffer to start at
- mov al, char
- mov ah, attr ; Load current display attribute
- mov es, vinfo.sgmnt ; Load video segment
- cld
- rep stosw ; Write the chars
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vwnEnd
- call MouseShow
- ENDIF
- vwnEnd:
- ret
- VidWrtCharN ENDP
- ;/*****************************************************************************
- ;* VidGetColor() - Returns current text color
- ;*
- ;* Notes
- ;* Params
- ;* None.
- ;* Return
- ;* Returns CLR2 current color
- ;*****************************************************************************/
- VidGetColor PROC
- xor ax, ax
- mov al, attr
- ret
- VidGetColor ENDP
- ;/*****************************************************************************
- ;* VidSetColor() - Sets current text color
- ;*
- ;* Notes
- ;* Params
- ;* CLR2 color : Color to set it to
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidSetColor PROC clr:BYTE
- mov al, clr
- mov attr, al
- ret
- VidSetColor ENDP
- ;/*****************************************************************************
- ;* VidShowCursor() - Shows/hides the cursor
- ;*
- ;* Params
- ;* bool bShow : TRUE if show cursor, FALSE if hide
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidShowCursor PROC bShow:WORD
- mov ax, bShow
- IFDEF MONO_2
- ;; Are we using debug monitor? If so, bypass bios.
- cmp mseg, 0h
- jz vscUseBios
- call MDAShowCursor
- jmp short vscExit1
- vscUseBios:
- ENDIF
- or ax, ax
- jz vscHidecur
- mov cx, vinfo.curStd
- mov vinfo.fShowCursor, 01h
- jmp short vscDoit
- vscHidecur:
- mov cx, 2000h
- mov vinfo.fShowCursor, 00h
- vscDoit:
- ;;
- ;; _Interrupt_List_ says that AMI 386 BIOS and AST Premier 386 BIOS will
- ;; lock up the system if AL is not equal to the current video mode.
- ;;
- mov al, vinfo.mode
- mov ah, 01h
- call VideoBios
- vscExit1:
- ret
- VidShowCursor ENDP
- ;/*****************************************************************************
- ;* VidSetCurType() - Sets insert or overwrite cursor
- ;*
- ;* Params
- ;* bool bInsert : TRUE for insert, FALSE for overwrite
- ;* Return
- ;* None.
- ;*****************************************************************************/
- ;;
- ;; BUGBUG: There's supposed to be some sort of EGA 43-line-mode BIOS bug
- ;; here, but i can't find any details on it. The code to handle it is
- ;; sort of large, so i'm leaving it out for now. If someone complains,
- ;; i may implement it.
- ;;
- VidSetCurType PROC bInsert:WORD
- mov cx, vinfo.curInsert
- cmp bInsert, 0
- jnz vsc1
- mov cx, vinfo.curOverwrite
- vsc1:
- mov vinfo.curStd, cx
- cmp vinfo.fShowCursor, 00h ; Cursor currently hidden?
- jz vscExit ; If so, then don't really set it
- ;;
- ;; _Interrupt_List_ says that AMI 386 BIOS and AST Premier 386 BIOS will
- ;; lock up the system if AL is not equal to the current video mode.
- ;;
- mov al, vinfo.mode
- mov ah, 01h
- call VideoBios
- vscExit:
- ret
- VidSetCurType ENDP
- ;/*****************************************************************************
- ;* VidSetCurPos() - Sets cursor position
- ;*
- ;* Params
- ;* uint cy : row to move to
- ;* uint cx : column to move to
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidSetCurPos PROC y:WORD, x:WORD
- mov dx, x
- mov ax, y
- IFDEF MONO_2
- ;; Are we using debug monitor? If so, bypass bios.
- cmp mseg, 0h
- jz vscpUseBios
- call MDASetCurPos
- jmp short vscpExit1
- vscpUseBios:
- ENDIF
- mov dh, al
- mov ax, 0200h
- mov bh, vinfo.dpage
- call VideoBios
- vscpExit1:
- ret
- VidSetCurPos ENDP
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; CheckMouse() - Checks if mouse would be overwritten, and checks params.
- ;;
- ;; Params
- ;; BX : Ptr to RECT structure
- ;; Return
- ;; Carry : Set if error, Clear if ok.
- ;;
- ;; Registers Destroyed
- ;; AX, CX, DX, and Flags may be destroyed.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- CheckMouse:
- IFDEF MOUSE_SUPPORT
- ;; Check if cursor would be overwritten
- ;;
- ;; Since the mouse moves at interrupt-time, it's possible for it to move
- ;; DURING a video i/o call, after we've done our check here. Only appears
- ;; to be a real problem during large scroll operations, that take a large
- ;; amount of time (and that make mouse droppings very noticeable).
- ;; For now, i'm adding a little fudge-factor (2 rows/cols) that hopefully
- ;; should handle it.
- ;; cxMouse/cyMouse are set at interrupt-time by mouse handler.
- ;;
- mov ax, cxMouse
- add ax, 2 ; Fudge factor
- cmp ax, [bx].RECT.left ; Cursor before starting column?
- jl cmNoHide
- sub ax, 3 ; Opposite fudge factor.
- cmp ax, [bx].RECT.right ; Cursor after ending column?
- jg cmNoHide
- mov ax, cyMouse
- add ax, 2 ; Fudge factor
- cmp ax, [bx].RECT.top ; Cursor before starting row?
- jl cmNoHide
- sub ax, 3 ; Opposite fudge factor.
- cmp ax, [bx].RECT.bottom ; Cursor after ending row?
- jg cmNoHide
- push bx ; Save rect ptr
- call MouseHide ; If not, it'd be overwritten
- pop bx ; Restore rect ptr
- mov BYTE PTR fUpdateMouse, 01h
- cmNoHide:
- ENDIF
- clc
- cmExit1:
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; SetupBlock() - Internal function.
- ;;
- ;; Params
- ;; BX : Ptr to RECT
- ;; Returns
- ;; Carry : Set if error, Clear if ok.
- ;;
- ;; BX : Start address for 1st line
- ;; CX : Line length (in chars)
- ;; DX : cxLineLen * 2
- ;; SI : #of lines to process
- ;; DI : Starting read/write offset
- ;; BP : Line length (in chars)
- ;; ES : video buffer segment
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- SetupBlock:
- call CheckMouse
- jc sbExit1
- mov ax, [bx].RECT.top
- mov dx, [bx].RECT.left
- mov cx, [bx].RECT.right
- mov bx, [bx].RECT.bottom
- mov si, bx ; Calculate number of lines
- sub si, ax
- mul BYTE PTR vinfo.cols ; Calculate first line start
- add ax, dx
- shl ax, 1
- mov di, ax
- sub cx, dx ; Calculate line length
- mov bp, cx ; Save it in BP
- xor dx, dx
- mov dl, vinfo.cols ; Load columns * 2
- shl dx, 1
- mov bx, di ; Save line start
- mov es, vinfo.sgmnt ; Load video buffer segment
- cld
- clc
- sbExit1:
- ret
- ;/*****************************************************************************
- ;* VidFillBlock() - Fills block on screen with specified char/attr.
- ;*
- ;* Params
- ;* RECT *pr : Ptr to RECT struct containing block to clear
- ;* uint chFill : Char/attr to fill with (HIBYTE:Attr, LOBYTE:Char)
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidFillBlock PROC USES si di, pr:WORD, chFill:WORD
- push bp
- mov ax, chFill
- push ax
- mov bx, pr
- call SetupBlock
- pop ax ; Load char/attr to write
- ;;
- ;; ES:DI : Current read/write address
- ;; AX : Char/attr to write
- ;; BX : Start address for current line
- ;; CX : Scratch line length
- ;; DX : cxLineLen * 2
- ;; SI : # of lines left to process
- ;; BP : Length of line to write
- ;;
- even
- vfbLoop:
- dec si ; Decrement LinesLeftToDo
- rep stosw ; Write the line
- or si, si ; Any more lines to do?
- jz vfbEnd2
- add bx, dx ; Advance to next line
- mov cx, bp ; Reset line length
- mov di, bx ; Set r/w address to start of next line
- jmp SHORT vfbLoop
- vfbEnd2:
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vfbEnd
- call MouseShow
- ENDIF
- vfbEnd:
- pop bp
- ret
- VidFillBlock ENDP
- IFDEF QHELP
- ;; Don't include it!
- ELSEIFDEF QEDIT
- ;; Don't include it!
- ELSE
- ;/*****************************************************************************
- ;* VidInvert() - Inverts a block on screen
- ;*
- ;* Entry
- ;* RECT pRect : block to invert
- ;* Exit
- ;* None.
- ;*****************************************************************************/
- VidInvert PROC USES si di, pr:WORD
- push bp
- mov bx, pr
- call SetupBlock
- ;;
- ;; ES:DI : Current read/write address
- ;; AL : Char to write
- ;; AH : Attr to write
- ;; BX : Start address for current line
- ;; CX : Scratch line length
- ;; DX : cxLineLen * 2
- ;; SI : # of lines left to process
- ;; BP : Length of line to write
- ;;
- even
- viLoop:
- mov ax, es:[di] ; Load attr/char
- dec cx
- ;; Invert it by swapping foreground/background attributes
- rol ah, 4 ; Swap fg/bg attributes.
- and ah, 7Fh ; Make sure no blinking background
- stosw ; Store it back
- or cx, cx
- jnz viLoop
- dec si ; Decrement LinesLeftToDo
- or si, si ; Any more lines to do?
- jz viEnd2
- add bx, dx ; Advance to next line
- mov cx, bp ; Reset line length
- mov di, bx ; Set r/w address to start of next line
- jmp SHORT viLoop
- viEnd2:
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz viEnd
- call MouseShow
- ENDIF
- viEnd:
- pop bp
- ret
- VidInvert ENDP
- ENDIF
- ;/*****************************************************************************
- ;* VidSetAttr() - Sets attributes in a block, allowing shadow effects.
- ;*
- ;* Entry
- ;* RECT pRect : block to shadow
- ;* char attr : attribute to fill with
- ;* Exit
- ;* None.
- ;*****************************************************************************/
- VidSetAttr PROC USES si di, pr:WORD, attrib:BYTE
- push bp
- mov bx, pr
- xor ax, ax
- mov ah, attrib
- push ax
- call SetupBlock
- pop ax
- ;;
- ;; ES:DI : Current read/write address
- ;; AL : Current char
- ;; AH : New attribute
- ;; BX : Start address for current line
- ;; CX : Scratch line length
- ;; DX : cxLineLen * 2
- ;; SI : # of lines left to process
- ;; BP : Length of line to write
- ;;
- even
- vsLoop:
- mov al, es:[di] ; Load char
- dec cx
- stosw ; Store it back, along with new attr
- or cx, cx
- jnz vsLoop
- dec si ; Decrement LinesLeftToDo
- or si, si ; Any more lines to do?
- jz vsEnd2
- add bx, dx ; Advance to next line
- mov cx, bp ; Reset line length
- mov di, bx ; Set r/w address to start of next line
- jmp SHORT vsLoop
- vsEnd2:
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vsEnd
- call MouseShow
- ENDIF
- vsEnd:
- pop bp
- ret
- VidSetAttr ENDP
- ;/*****************************************************************************
- ;* VidGetBlockSize() - Calculates buf size needed to save screen region
- ;*
- ;* Params
- ;* RECT *pr : Ptr to RECT containing block to save.
- ;* Return
- ;* Buffer size in bytes, or 0 if error.
- ;*****************************************************************************/
- VidGetBlockSize PROC pr:WORD
- mov bx, pr
- ;; Calculate buffer size needed
- mov ax, [bx].RECT.bottom ; #of lines = Bottom - Top
- sub ax, [bx].RECT.top
- mov dx, [bx].RECT.right ; #of cols = Right - Left
- sub dx, [bx].RECT.left
- mul dl ; total chars = #of lines * #of cols
- shl ax, 1 ; Change units from chars to bytes
- add ax, SIZEOF BLOCK ; Add header size to buffer size
- vgbsExit1:
- ret
- VidGetBlockSize ENDP
- ;/*****************************************************************************
- ;* VidSaveBlock() - Saves part of screen to memory
- ;*
- ;* Params
- ;* RECT *pr : Ptr to RECT containing block to save.
- ;* void *pBuf : Buffer to save screen region into
- ;* Return
- ;* None.
- ;*****************************************************************************/
- ;* The saved block buffer has the following format :
- ;*
- ;* Header:
- ;* uint Screen offset of start of first line
- ;* uint Block line length in chars
- ;* uint Number of lines in block
- ;* Data:
- ;* Block bytes in row-major order. Both the chars and attrs are
- ;* saved (BYTE char, BYTE attr)
- ;*
- ;*****************************************************************************
- VidSaveBlock PROC USES si di, pr:WORD, pBuf:WORD
- mov bx, pr
- call CheckMouse
- ;;
- ;; AX : Start of first screen line
- ;; BX : Length in bytes of full-screen line
- ;; DX : Number of lines left to copy
- ;; BP : Saved line length
- ;;
- ;; CX : Scratch line length
- ;; SI : Src offset
- ;; DI : Dst offset
- ;; DS : Src seg
- ;; ES : Dst seg
- ;;
- mov dx, [bx].RECT.bottom ; Calculate number of lines to copy
- mov ax, [bx].RECT.top
- sub dx, ax
- mov di, [bx].RECT.left ; Calculate start of first screen line
- mul BYTE PTR vinfo.cols
- add ax, di
- shl ax, 1 ; Convert from chars to bytes
- mov si, ax ; Set up source start
- mov cx, [bx].RECT.right ; Calculate line length
- sub cx, di ; Right - Left
- ;; Initialize the buffer header
- mov bx, pBuf ; Load save-buffer address
- mov [bx].BLOCK.voffset, ax ; Base offset of region in video page
- mov [bx].BLOCK.ccols, cx ; # of columns in region
- mov [bx].BLOCK.clines, dx ; # of rows in region
- ;; Set up registers for copy. No local vars can be accessed after this
- ;; point!
- push bp
- cld
- mov bp, cx ; Save line length
- mov di, bx
- add di, SIZEOF BLOCK ; Advance past header to data field
- mov bx, ds ; ES gets data seg (destination)
- mov es, bx
- xor bh, bh ; Calculate full-screen line length
- mov bl, vinfo.cols
- shl bx, 1
- mov ds, vinfo.sgmnt ; DS gets source seg
- even
- ;; Copy the lines
- vsbLoop:
- dec dx ; Decrement lines-left counter
- rep movsw ; Copy a line
- or dx, dx ; More lines to copy?
- jz vsbEnd1 ; If not, exit.
- add ax, bx ; Advance to next screen line
- mov cx, bp ; Reset line length
- mov si, ax
- jmp short vsbLoop
- vsbEnd1:
- mov ax, es ; Restore DS
- mov ds, ax
- pop bp
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vsbEnd2
- call MouseShow
- ENDIF
- vsbEnd2:
- ret
- VidSaveBlock ENDP
- ;/*****************************************************************************
- ;* VidRestoreBlock() - Restores screen block from memory
- ;*
- ;* Params
- ;* HBLOCK pb : Block to restore
- ;* Return
- ;* None.
- ;* Notes
- ;* The block must have been previously saved with VidSaveBlock().
- ;* VidRestoreBlock() does NOT free the block buffer.
- ;*****************************************************************************/
- VidRestoreBlock PROC USES si di, pb:WORD
- ;;
- ;; AX : Saved line length
- ;; BX : Full-screen line length
- ;; DX : Number of lines left to copy
- ;; BP : Line starting address
- ;;
- ;; CX : Scratch line length
- ;; SI : Src offset
- ;; DI : Dst offset
- ;; DS : Src seg
- ;; ES : Dst seg
- ;;
- IFDEF MOUSE_SUPPORT
- call MouseHide
- ENDIF
- push bp
- mov bx, pb
- ;; Read buffer header and set up registers for copy
- mov si, bx ; Advance SI to data field
- add si, SIZEOF BLOCK
- mov di, [bx].BLOCK.voffset ; Load screen starting address
- mov bp, di ; Save it
- mov cx, [bx].BLOCK.ccols ; Load line length
- mov ax, cx ; Save it
- mov dx, [bx].BLOCK.clines ; Load number of lines in block
- xor bh, bh
- mov bl, vinfo.cols ; Calculate full-screen line length
- shl bx, 1
- mov es, vinfo.sgmnt
- cld
- even
- ;; Copy the lines
- vrbLoop:
- dec dx ; Decrement lines-left counter
- rep movsw ; Copy a line
- or dx, dx ; Any more lines to copy?
- jz vrbEnd1 ; If not, exit.
- mov cx, ax ; Reset line length
- add bp, bx ; Advance to next line
- mov di, bp
- jmp SHORT vrbLoop
- vrbEnd1:
- pop bp
- IFDEF MOUSE_SUPPORT
- call MouseShow
- ENDIF
- ret
- VidRestoreBlock ENDP
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; SetupScroll() - Internal function.
- ;;
- ;; Params
- ;; AX : delta
- ;; BX : Ptr to RECT
- ;; Returns
- ;; AX : cbLine
- ;; DI : cbDelta
- ;; BX : Ptr to RECT
- ;; CX : #of chars in line
- ;; DX : #of lines to move
- ;; SI : rect.left
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- SetupScroll:
- mov dx, [bx].RECT.left
- mov cx, [bx].RECT.right
- sub cx, dx ; Calculate line length
- mov si, dx ; Save rect.left temporarily
- mov dx, [bx].RECT.bottom ; Calculate number of lines to move
- sub dx, [bx].RECT.top
- sub dx, ax
- mul BYTE PTR vinfo.cols ; Calculate distance from dest to src
- shl ax, 1
- mov di, ax
- xor ax, ax ; Precalculate full-screen line length
- mov al, vinfo.cols
- shl ax, 1
- mov es, vinfo.sgmnt ; Load seg registers
- ret
- ;/*****************************************************************************
- ;* VidScrollDown() - scrolls screen down N lines
- ;*
- ;* Params
- ;* RECT *pr : Block to scroll
- ;* uint delta : #of lines to scroll
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidScrollDown PROC USES si di,
- pr:WORD, delta:WORD
- LOCAL cbDelta:WORD, cbLine:WORD
- mov bx, pr
- call CheckMouse
- ; RECT containing new coords returned in BX
- mov ax, delta
- call SetupScroll
- mov cbDelta, di
- mov cbLine, ax
- mov ax, [bx].RECT.top
- mul BYTE PTR vinfo.cols ; Calculate starting line start
- add ax, si
- shl ax, 1
- mov di, ax
- mov si, ax ; Calculate src start
- add si, cbDelta
- mov bx, di ; Save line start
- mov ax, cx ; Save line length
- push ds ; Save DS
- mov ds, vinfo.sgmnt
- cld
- ;;
- ;; AX : Line length (in chars)
- ;; BX : Current line start
- ;; CX : Scratch line length
- ;; DX : Number of lines left to process
- ;; SI : Source
- ;; DI : Dest
- ;; cxLine : #of bytes in screen line
- ;; cbDelta : Distance from dest to src
- ;;
- even
- vsdLoop1:
- dec dx ; Decrement lines-left counter
- rep movsw
- add bx, cbLine ; Advance to next line
- mov di, bx
- mov si, bx
- add si, cbDelta
- mov cx, ax ; Reset line length
- or dx, dx ; More lines to copy?
- jz vsdDone1
- jmp short vsdLoop1
- ;;
- ;; Now clear the last lines
- ;;
- vsdDone1:
- pop ds ; Restore DS
- mov si, ax ; SI just opened up, give it LineLength
- mov ah, attr ; Load Space char/attr
- mov al, SPACE
- mov dx, delta ; #of lines to clear
- ;;
- ;; AX : Attr:Space
- ;; BX : Current line start
- ;; CX : Scratch line length
- ;; DX : Number of lines left to clear
- ;; SI : Line length (in chars)
- ;; DI : Dest
- ;; cbLine : #of bytes in screen line
- ;;
- vsdLoop2:
- mov di, bx ; DI = start of current line
- mov cx, si ; Reset line length
- dec dx ; Decrement lines-left counter
- rep stosw
- or dx, dx ; More lines to clear?
- jz vsdExit2
- add bx, cbLine ; Advance to next line
- mov di, bx
- jmp short vsdLoop2
- vsdExit2:
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vsdExit1
- call MouseShow
- ENDIF
- vsdExit1:
- ret
- VidScrollDown ENDP
- ;/*****************************************************************************
- ;* VidScrollUp() - scrolls screen up N lines
- ;*
- ;* Params
- ;* RECT *pr : Block to scroll
- ;* uint delta : #of lines to scroll
- ;* Return
- ;* None.
- ;*****************************************************************************/
- VidScrollUp PROC USES si di,
- pr:WORD, delta:WORD
- LOCAL cbDelta:WORD, cbLine:WORD
- mov bx, pr
- call CheckMouse
- ; RECT containing new coords returned in BX
- mov ax, delta
- call SetupScroll
- mov cbDelta, di
- mov cbLine, ax
- mov ax, [bx].RECT.top ; Calculate addr of 1st line to move
- add ax, dx ; rect.top + # lines to move = 1st line
- dec ax
- mul BYTE PTR vinfo.cols ; * #of cols = start of line (in chars)
- add ax, si ; + rect.left
- shl ax, 1 ; Convert from chars to bytes
- mov si, ax
- mov di, ax ; Calculate dest start
- add di, cbDelta ; SrcStart + cbDelta = DestStart
- mov bx, di ; And save it to BX too
- mov ax, cx ; Save line length
- push ds ; Save DS
- mov ds, vinfo.sgmnt
- cld
- ;;
- ;; AX : Line length (in chars)
- ;; BX : Current line start
- ;; CX : Scratch line length
- ;; DX : Number of lines left to process
- ;; SI : Source
- ;; DI : Dest
- ;; cxLine : #of bytes in screen line
- ;; cbDelta : Distance from dest to src
- ;;
- even
- vsuLoop1:
- dec dx ; Decrement lines-left counter
- rep movsw
- sub bx, cbLine ; Advance to next (previous) line
- mov si, bx
- mov di, bx
- sub si, cbDelta
- mov cx, ax ; Reset line length
- or dx, dx ; More lines to copy?
- jz vsuDone1
- jmp short vsuLoop1
- ;;
- ;; Now clear the last lines
- ;;
- vsuDone1:
- pop ds ; Restore DS
- mov si, ax ; SI just opened up, give it LineLength
- mov ah, attr ; Load Space char/attr
- mov al, SPACE
- mov dx, delta ; #of lines to clear
- ;;
- ;; AX : Attr:Space
- ;; BX : Current line start
- ;; CX : Scratch line length
- ;; DX : Number of lines left to clear
- ;; SI : Line length (in chars)
- ;; DI : Dest
- ;; cbLine : #of bytes in screen line
- ;;
- vsuLoop2:
- mov di, bx ; DI = start of current line
- mov cx, si ; Reset line length
- dec dx ; Decrement lines-left counter
- rep stosw
- or dx, dx ; More lines to clear?
- jz vsuExit2
- sub bx, cbLine ; Advance to next (previous) line
- mov di, bx
- jmp short vsuLoop2
- vsuExit2:
- IFDEF MOUSE_SUPPORT
- ;; If mouse may have been overwritten, then redisplay it
- cmp BYTE PTR fUpdateMouse, 00h
- jz vsuExit1
- call MouseShow
- ENDIF
- vsuExit1:
- ret
- VidScrollUp ENDP
- ;/*****************************************************************************
- ;* Beep() - Beeps the speaker
- ;*
- ;* Params
- ;* None
- ;* Return
- ;* None.
- ;*****************************************************************************/
- Beep PROC
- mov ax, 0E07h
- mov bh, vinfo.dpage
- mov bl, 0
- call VideoBios
- ret
- Beep ENDP
- END
Add Comment
Please, Sign In to add comment