📄 llvga.asm
字号:
; current attribute. This is identical to SetC_13 except that
; this routine assumes ES is set to video segment.
;Entry:
; ES = video segment (set up by b$SetPixFirstC)
; b$OffC specifies pixel to set
; b$AttrC = attribute to use
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub SetPixC_13
cProc SetPixC_13,<NEAR>
cBegin
mov al,b$AttrC ;[al] = attribute
mov bx,b$OffC ;[BX] = cursor offset
;[ES] = setup by SetPixFirstC
mov es:[bx],al ;set color value
cEnd
;NOTE: SetPixFirstC, SetPixLastC use CGA
;***
; LineX_13
;
;Purpose:
; Draw an X-major line for Screen 13.
;Entry:
; AH = color (b$AttrC)
; AL = bit accumulator (0)
; BX = major axis delta update value (Incr1)
; CX = point count
; DX = BP change for Y movement
; SI = delta decision value
; DI = line style
; BP = video offset
; ES = video segment
; Incr2 = minor axis delta update value
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub LineX_13
cProc LineX_13,<NEAR>
cBegin
mov bx,b$Incr1 ;to register here
Line13Xloop:
ROL DI,1 ;next line style bit
JNC Line13X2 ;go if bit is 0 not to plot
mov es:[bp],ah ;set this pixel
Line13X2:
OR SI,SI ;time to move in Y (+ or 0 delta)?
JNS Line13X4 ;go if so
ADD SI,BX ;update delta for X movement
INC BP ;go to next byte
loop Line13Xloop
ret
Line13X4:
ADD SI,b$Incr2 ;update delta for Y movement
inc bp ;move to next X
add BP,DX ;move to next Y
loop Line13Xloop ;go for more
cEnd
;***
; LineY_13
;
;Purpose:
; Draw a Y-major line for Screen 13.
;Entry:
; AH = color (b$AttrC)
; BX = major axis delta update value (Incr1)
; CX = point count
; DX = BP change for Y movement (swapped with IncrY)
; SI = delta decision value
; DI = line style
; BP = video offset
; ES = video segment
; Incr2 = minor axis delta update value
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub LineY_13
cProc LineY_13,<NEAR>
cBegin
mov bx,b$Incr1 ;to register here
Line13Yloop:
ROL DI,1 ;next line style bit
JNC Line13Y2 ;go if bit is 0 not to plot
mov es:[bp],ah ;set this pixel
Line13Y2:
OR SI,SI ;time to move in X (+ or 0 delta)?
JNS Line13Y3 ;go if so
ADD SI,BX ;update delta for Y movement
ADD BP,DX ;move to next Y
loop Line13Yloop
ret
Line13Y3:
ADD SI,b$Incr2 ;update delta for X movement
inc bp ;move to next X
add BP,DX ;move to next Y
loop Line13Yloop ;go for more
cEnd
;***
; LineV_13
;
;Purpose:
; Draw a vertical line for Screen 13.
;Entry:
; AH = color (b$AttrC)
; CX = point count
; DX = BP change for Y movement
; SI = IncrY = BP change for Y movement
; DI = line style
; BP = video offset
; ES = video segment
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub LineV_13
cProc LineV_13,<NEAR>
cBegin
MOV SI,b$IncrY ;to register here
Line13Vloop:
ROL DI,1 ;next line style bit
JNC Line13V2 ;go if bit is 0 not to plot
mov es:[bp],ah ;set this pixel
Line13V2:
ADD BP,DX ;to next Y
LOOP Line13Vloop ;go for more
cEnd
labelW PutTable_13 ;Put Vectors according to put action value
DW PutOr_13, PutAnd_13, PutPreset_13, B$BumpDS ,PutXor_13
;B$BumpDS entry is signal for PSET to use faster movsb and
;becomes the array segment bumper for NRWMove
;***
; PutAction_13
;
;Purpose:
; Set b$PutVector to appropriate PUT action routine for Screen 13.
; Requested action is used to index into a table of entry points.
;Entry:
; AL = PUT action [0..4] representing (OR, AND, PRESET, PSET, XOR)
;Exit:
; b$PutVector set to entry point of appropriate PUT action routine
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub PutAction_13
cProc PutAction_13,<NEAR>
cBegin
xor ah,ah ;make word index
shl ax,1
mov bx,ax
mov ax,cs:PutTable_13[BX] ;get our vector
mov b$PutVector,ax ;save it
cEnd
ASSUME DS:NOTHING
;***
; NReadL_13
;
;Purpose:
; Read a line of pixels from the screen to an array for Screen 13.
;Entry:
; DS:SI = screen address
; ES:DI = array address
; BP = count of bits (not pixels) to read
;Exit:
; ES:DI = updated to array byte past point filled
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub NReadL_13
cProc NReadL_13,<NEAR>
cBegin
mov cx,bp ;convert bit count to byte count in cx
shr cx,1
shr cx,1
shr cx,1
mov bx,GR_TEXTOFFSET B$BumpES ;array segment bumper
mov dx,di ;dx = array offset
NRWMove:
neg dx ;compute space remaining in array's segment
cmp cx,dx ;enough room?
ja NRdOvl ;go if not, segment will overflow
NRWNoOvl:
rep movsb ;move remainder
cEnd
NRdOvl:
sub cx,dx ;compute overflow count
xchg cx,dx ;use remaining segment space as move count
rep movsb ;move to end of segment
xchg cx,dx ;use overflow count for second move
;NOTE: only two moves are required since a MODE 13 screen is < 64K
; and could only cross one segment boundary
call bx ;move array pointer over segment boundary
jmp short NRWNoOvl
;***
; NWriteL_13
;
;Purpose:
; Write a line of pixels from an array to the screen for Screen 13.
;Entry:
; ES:DI = screen address
; DS:SI = array address
; BP = count of bits (not pixels) to write
;Exit:
; DS:SI = updated to array byte past point used
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub NWriteL_13
cProc NWriteL_13,<NEAR>
cBegin
.erre ID_SSEQDS ;assumes ss = ds
mov bx,ss:[b$PutVector] ;preload the put routine address
mov dx,si ;dx = array offset for NRWMove
mov cx,bp ;convert bit count to byte count in cx
shr cx,1
shr cx,1
shr cx,1
cmp bx,GR_TEXTOFFSET B$BumpDS ;is this for PSET?
jz NRWMove ;go if so
NWrLoop13:
lodsb ;load byte from array
or si,si ;array pointer overflowed to next segment?
jz NWrOvfl2 ;go if so
jmp bx ;put the byte
;
;The following Put routines perform the actual logical operation where
; [AL] = data value
; [ES:DI] = screen address
;
;
; PutAnd_13
;
PutAnd_13:
and es:[di],al ;AND WITH SCREEN
jmp short PutEnd
;
; PutOr_13
;
PutOr_13:
or es:[di],al ;OR WITH SCREEN
jmp short PutEnd
;
; PutPreset_13
;
PutPreset_13:
not al ;NEGATE DATA FOR PRESET
stosb ;set screen pixel
jmp short PutEnd2
;
; PutXor_13
;
PutXor_13:
xor es:[di],al ;XOR WITH SCREEN
PutEnd:
inc di
PutEnd2:
loop NWrLoop13
cEnd
NWrOvfl2:
call B$BumpDS ;move array pointer over segment boundary
jmp bx ;put the byte
ASSUME DS:DGROUP
;***
; NSetC_13
;
;Purpose:
; Set a horizontal line of pixels to the current attribute for
; Screen 13. The line starts at the current cursor position
; and moves right.
;Entry:
; b$AddrC specifies start pixel
; b$AttrC specifies attribute to use
; BX = pixel count
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub NSetC_13
cProc NSetC_13,<NEAR>,<ES,DI>
cBegin
les di,b$AddrC ;graphics cursor address
mov al,b$AttrC ;al = attribute
mov cx,bx ;cx = pixel count
rep stosb ;block write full bytes
NSetExit:
cEnd
;***
; PaintBound_13
;
;Purpose:
; Called by PAINT before painting each scan line to facilitate
; fast viewport edge detection. Set VIEW left and right cursor
; addresses.
;Entry:
; b$OffC specifies current cursor position
;Exit:
; B$LEOFST = left edge offset
; B$REOFST = right edge offset
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub PaintBound_13
cProc PaintBound_13,<NEAR>
cBegin
MOV AX,b$OffC ;get cursor position
; Compute the addr of the 1st pixel on the line by computing the
; line number and then multiplying by BytesPerRow
; LineNumber = INT(OffC/BytesPerRow)
; first pixel in line = LineNumber * BytesPerRow
xor dx,dx
MOV cx,320 ;LineNumber = INT(OffC/BytesPerRow)
DIV cx
mov bx,ax ;multiply y by 320 to compute row displacement
shl ax,1 ;dx=2*Y
shl ax,1 ;dx=4*Y
add ax,bx ;dx=5*Y
mov cl,6
shl ax,cl ;dx=5*Y*64=320*Y
mov dx,ax
; b$OffC addr of 1st pixel in current row is now in DX - compute boundries
MOV AX,B$VLOFST
ADD AX,DX
MOV B$LEOFST,AX ;Left margin= (x1,0)+b$OffC
add dX,B$VROFST
MOV B$REOFST,dx ;Right margin= (x2,0)+b$OffC
cEnd
;NOTE: SetTile use CGA
;***
; ScanL_13
;
;Purpose:
; For Screen 13, scan left beginning with the pixel to the left
; of cursor, and paint pixels until:
; (1) the viewport edge is encounteered (edge painted)
; (2) a border pixel is encountered (border not painted)
;
;Entry:
; b$AddrC = pixel to right of starting pixel
; b$PaintBorder = attribute of paint region border
; b$AttrC = attribute to paint
; B$LEOFST = left viewport edge
;Exit:
; BX = number of pixels scanned
; CL = 0 iff no pixels changed color
; b$OffC = the last non-border pixel examined/painted
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub ScanL_13
cProc ScanL_13,<NEAR>,<DX,DI,ES>
cBegin
les di,b$AddrC ;di=cursor offset, es=video seg
mov dl,b$PaintBorder ;dl=border attribute
mov dh,b$AttrC ;dh=paint attribute
xor cx,cx ;cx=clear already-painted-flag
xor bx,bx ;bx=clear paint count
; The registers are set up and used as follows:
; ES:DI = Video segment address (b$AddrC)
; DL = border attribute
; DH = paint attribute
; CL = already painted flag
; AL = screen byte
; BX = paint count
; Scan left beginning with the pixel to the left of the cursor,
; and paint pixels until:
; 1. edge of screen/VIEWPORT is encountered (edge painted)
; 2. a border pixel is encountered (border not painted)
SL13Loop:
cmp di,B$LEOFST ;are we at left viewport edge?
je SL13Edge ;exit if so, can't go left
dec di ;move left one byte
mov al,es:[di] ;get the screen byte
cmp al,dl ;screen byte == border?
je SL13Border ;go if border
xor al,dh ;AL = 0 if screen byte == paint attribute
or cl,al ;set the already-painted-flag
inc bx ;increment paint count
jmp short SL13Loop ;keep going
SL13Border:
inc di ;back up away from the border
SL13Edge:
mov b$OffC,di ;paint start point
or bx,bx ;any pixels to paint
jz SL13NoSet ;go if none
push bx
push cx
call NSetC_13 ;paint 'em all at once (and tile)
pop cx
pop bx
SL13NoSet:
; Scan encountered a border pixel or viewport edge,
; now exit with:
; BX = number of pixels scanned
; CL = 0 iff no pixels changed color
cEnd
;***
; ScanR_13
;
;Purpose:
; For Screen 13, starting with the current pixel, search right until:
; (1) a non-border pixel is found
; (2) [DX] pixels have been tested
; (3) the viewport edge is encountered
;
; If (2) or (3) terminated the scan, exit with:
; DX = remaining border bount = 0
;
; If (1) terminated the scan, scan and paint non-border pixels until:
; (1) the viewport edge is encountered (edge painted)
; (2) a border pixel is encountered (border not painted)
;
;Entry:
; DX = count of border pixels which may be skipped
; b$AddrC = starting pixel
; b$PaintBorder = attribute of paint region border
; b$AttrC = attribute to paint
; B$REOFST = right viewport edge
;Exit:
; BX = number of pixels painted
; (whether or not they changed color)
; CL = 0 iff no pixels changed color
; DX = remaining border pixel count
; b$OffC = the last non-border pixel examined/painted
; SI, AL = the first non-border pixel encountered
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
DbPub ScanR_13
cProc ScanR_13,<NEAR>,<DI,BP,ES>
cBegin
mov bx,dx ;bx=skip count
les di,b$AddrC ;di=cursor offset, es=video seg
mov dl,b$PaintBorder ;dl=border attribute
mov dh,b$AttrC ;dh=paint attribute
xor cx,cx ;cl=clear already-painted-flag
; The registers are set up as follows:
; ES:DI = Video segment address (b$AddrC)
; DL = border attribute
; DH = paint attribute
; CL = already painted flag
; AL = screen byte
; Starting with the current pixel, scan right until:
; 1. [BX] pixels have been tested
; 2. edge of screen/VIEWPORT is encountered
; 3. a non-BORDER pixel is found
SR13Loop1:
mov al,es:[di] ;get screen byte
cmp al,dl ;screen byte == border?
jnz SR13Paint ;go if not
dec bx ;decrement border count
jz SR13NoCnt ;brif border count zero
inc di ;move right one pixel
cmp di,B$REOFST ;past viewport edge?
jbe SR13Loop1 ;go if not, keep scanning
dec di ;back to edge
xor bx,bx ;pretend to run out of skip count
SR13NoCnt:
; [BX] pixels have been tested, or the viewport edge encountered,
; now exit with:
; BX = number of pixels painted = 0
; CL = already painted flag = 0
; DX = border count = 0
mov dx,bx ;return skip count = 0, and no pixels painted
jmp short SR13Exit ;go exit
; Original scan encountered a non-border pixel.
; Now scan and paint non-border pixels until:
; 1. edge of screen/VIEWPORT is encountered (edge painted)
; 2. a border pixel is encountered (border not painted)
SR13Paint:
mov b$SaveCa,di ;saving _bSaveCa
mov b$OffC,di ;set the cursor offset for paint start
push bx ;save border count
xor bx,bx ;clear paint count
SR13Loop2:
cmp di,B$REOFST ;past viewport edge?
ja SR13Edge ;go if so
mov al,es:[di] ;[al] = screen byte
cmp al,dl ;screen byte == border?
je SR13Border ;go if so
XOR al,DH ;detect any differences from paint color
OR cl,al ;combine with the already painted flag
inc bx ;increment paint count
INC DI ;move right by one byte
JMP SHORT SR13Loop2 ;keep scanning and counting
SR13Edge:
dec di ;back up
SR13Border:
or bx,bx ;any pixels to paint
jz SR13NoSet ;go if none
push bx
push cx
call NSetC_13 ;paint 'em all at once (and tile)
pop cx
pop bx
SR13NoSet:
pop dx ;return skip count
; Second scan encountered a border pixel or viewport edge,
; now exit with:
; BX = count of pixels painted
; (whether or not they changed color)
; CL = 0 iff no pixels changed color
; DX = count of BORDER pixels searched in the first search
; b$OffC = the last pixel examined/painted
; SI = specifies the first non-BORDER pixel encountered
SR13Exit:
mov b$OffC,di ;return cursor offset
mov si,b$SaveCa ;returning b$SaveCa
cEnd
;***
; B$xINITVGA - initialize VGA modes
;
;Purpose:
; Added with revision [10].
; Put the addresses of VGA screen mode support routines into the
; dispatch table used by the screen statement.
;
;Entry:
; None
;Exit:
; ScreenTab updated
;Uses:
; None
;Exceptions:
;******************************************************************************
cProc B$xINITVGA,<FAR,PUBLIC>
cBegin
MOV WORD PTR [b$ScreenTab + (11*2) + 1],OFFSET B$Screen11
MOV WORD PTR [b$ScreenTab + (12*2) + 1],OFFSET B$Screen12
MOV WORD PTR [b$ScreenTab + (13*2) + 1],OFFSET B$Screen13
cEnd
sEnd GR_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -