364 lines
13 KiB
Markdown
364 lines
13 KiB
Markdown
"That's an interesting application of write mode 2," you may well say,
|
||
"but is it really useful?" While the ability to convert chunky bitmaps
|
||
into VGA bitmaps does have its uses, Listing 27.1 is primarily intended
|
||
to illustrate the mechanics of write mode 2.
|
||
|
||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
 *For performance, it's best to store 16-color bitmaps in pre-separated four-plane format in system memory, and copy one plane at a time to the screen. Ideally, such bitmaps should be copied one scan line at a time, with all four planes completed for one scan line before moving on to the next. I say this because when entire images are copied one plane at a time, nasty transient color effects can occur as one plane becomes visibly changed before other planes have been modified.*
|
||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
#### Drawing Color-Patterned Lines Using Write Mode 2 {#Heading6}
|
||
|
||
A more serviceable use of write mode 2 is shown in the program presented
|
||
in Listing 27.2. The program draws multicolored horizontal, vertical,
|
||
and diagonal lines, basing the color patterns on passed color tables.
|
||
Write mode 2 is ideal because in this application color can vary from
|
||
one pixel to the next, and in write mode 2 all that's required to set
|
||
pixel color is a change of the lower nibble of the byte written by the
|
||
CPU. Set/reset could be used to achieve the same result, but an
|
||
index/data pair of **OUT**s would be required to set the Set/Reset
|
||
register to each new color. Similarly, the Map Mask register could be
|
||
used in write mode 0 to set pixel color, but in this case not only would
|
||
an index/data pair of **OUT**s be required but there would also be no
|
||
guarantee that data already in display memory wouldn't interfere with
|
||
the color of the pixel being drawn, since the Map Mask register allows
|
||
only selected planes to be drawn to.
|
||
|
||
Listing 27.2 is hardly a comprehensive line drawing program. It draws
|
||
only a few special line cases, and although it is reasonably fast, it is
|
||
far from the fastest possible code to handle those cases, because it
|
||
goes through a dot-plot routine and because it draws horizontal lines a
|
||
pixel rather than a byte at a time. Write mode 2 would, however, serve
|
||
just as well in a full-blown line drawing routine. For any type of
|
||
patterned line drawing on the VGA, the basic approach remains the same:
|
||
Use the bit mask to select the pixel (or pixels) to be altered and use
|
||
the CPU byte in write mode 2 to select the color in which to draw.
|
||
|
||
**LISTING 27.2 L27-2.ASM**
|
||
|
||
; Program to illustrate one use of write mode 2 of the VGA and EGA by
|
||
; drawing lines in color patterns.
|
||
;
|
||
; Assemble with MASM or TASM
|
||
;
|
||
; By Michael Abrash
|
||
;
|
||
Stack segment para stack ‘STACK'
|
||
db 512 dup(0)
|
||
Stack ends
|
||
|
||
SCREEN_WIDTH_IN_BYTES equ 80
|
||
GRAPHICS_SEGMENT equ 0a000h ;mode 10 bit-map segment
|
||
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
||
MAP_MASK equ 2 ;index of Map Mask register
|
||
GC_INDEX equ 03ceh ;Graphics Controller Index reg
|
||
GRAPHICS_MODE equ 5 ;index of Graphics Mode reg
|
||
BIT_MASK equ 8 ;index of Bit Mask reg
|
||
|
||
Data segment para common ‘DATA'
|
||
Pattern0 db 16
|
||
db 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||
db 9, 10, 11, 12, 13, 14, 15
|
||
Pattern1 db 6
|
||
db 2, 2, 2, 10, 10, 10
|
||
Pattern2 db 8
|
||
db 15, 15, 15, 0, 0, 15, 0, 0
|
||
Pattern3 db 9
|
||
db 1, 1, 1, 2, 2, 2, 4, 4, 4
|
||
Data ends
|
||
|
||
Code segment para public ‘CODE'
|
||
assume cs:Code, ds:Data
|
||
Start proc near
|
||
mov ax,Data
|
||
mov ds,ax
|
||
mov ax,10h
|
||
int 10h ;select video mode 10h (640x350)
|
||
;
|
||
; Draw 8 radial lines in upper-left quadrant in pattern 0.
|
||
;
|
||
mov bx,0
|
||
mov cx,0
|
||
mov si,offset Pattern0
|
||
call QuadrantUp
|
||
;
|
||
; Draw 8 radial lines in upper-right quadrant in pattern 1.
|
||
;
|
||
mov bx,320
|
||
mov cx,0
|
||
mov si,offset Pattern1
|
||
call QuadrantUp
|
||
;
|
||
; Draw 8 radial lines in lower-left quadrant in pattern 2.
|
||
;
|
||
mov bx,0
|
||
mov cx,175
|
||
mov si,offset Pattern2
|
||
call QuadrantUp
|
||
;
|
||
; Draw 8 radial lines in lower-right quadrant in pattern 3.
|
||
;
|
||
mov bx,320
|
||
mov cx,175
|
||
mov si,offset Pattern3
|
||
call QuadrantUp
|
||
;
|
||
; Wait for a key before returning to text mode and ending.
|
||
;
|
||
mov ah,01h
|
||
int 21h
|
||
mov ax,03h
|
||
int 10h
|
||
mov ah,4ch
|
||
int 21h
|
||
;
|
||
; Draws 8 radial lines with specified pattern in specified mode 10h
|
||
; quadrant.
|
||
;
|
||
; Input:
|
||
; BX = X coordinate of upper left corner of quadrant
|
||
; CX = Y coordinate of upper left corner of quadrant
|
||
; SI = pointer to pattern, in following form:
|
||
; Byte 0: Length of pattern
|
||
; Byte 1: Start of pattern, one color per byte
|
||
;
|
||
; AX, BX, CX, DX destroyed
|
||
;
|
||
QuadrantUp proc near
|
||
add bx,160
|
||
add cx,87 ;point to the center of the quadrant
|
||
mov ax,0
|
||
mov dx,160
|
||
call LineUp ;draw horizontal line to right edge
|
||
mov ax,1
|
||
mov dx,88
|
||
call LineUp ;draw diagonal line to upper right
|
||
mov ax,2
|
||
mov dx,88
|
||
call LineUp ;draw vertical line to top edge
|
||
mov ax,3
|
||
mov dx,88
|
||
call LineUp ;draw diagonal line to upper left
|
||
mov ax,4
|
||
mov dx,161
|
||
call LineUp ;draw horizontal line to left edge
|
||
mov ax,5
|
||
mov dx,88
|
||
call LineUp ;draw diagonal line to lower left
|
||
mov ax,6
|
||
mov dx,88
|
||
call LineUp ;draw vertical line to bottom edge
|
||
mov ax,7
|
||
mov dx,88
|
||
call LineUp ;draw diagonal line to bottom right
|
||
ret
|
||
QuadrantUp endp
|
||
;
|
||
; Draws a horizontal, vertical, or diagonal line (one of the eight
|
||
; possible radial lines) of the specified length from the specified
|
||
; starting point.
|
||
;
|
||
; Input:
|
||
; AX = line direction, as follows:
|
||
; 3 2 1
|
||
; 4 * 0
|
||
; 5 6 7
|
||
; BX = X coordinate of starting point
|
||
; CX = Y coordinate of starting point
|
||
; DX = length of line (number of pixels drawn)
|
||
;
|
||
; All registers preserved.
|
||
;
|
||
; Table of vectors to routines for each of the 8 possible lines.
|
||
;
|
||
LineUpVectors label word
|
||
dw LineUp0, LineUp1, LineUp2, LineUp3
|
||
dw LineUp4, LineUp5, LineUp6, LineUp7
|
||
|
||
;
|
||
; Macro to draw horizontal, vertical, or diagonal line.
|
||
;
|
||
; Input:
|
||
; XParm = 1 to draw right, -1 to draw left, 0 to not move horz.
|
||
; YParm = 1 to draw up, -1 to draw down, 0 to not move vert.
|
||
; BX = X start location
|
||
; CX = Y start location
|
||
; DX = number of pixels to draw
|
||
; DS:SI = line pattern
|
||
;
|
||
MLineUp macro XParm, YParm
|
||
local LineUpLoop, CheckMoreLine
|
||
mov di,si ;set aside start offset of pattern
|
||
lodsb ;get length of pattern
|
||
mov ah,al
|
||
|
||
LineUpLoop:
|
||
lodsb ;get color of this pixel...
|
||
call DotUpInColor ;...and draw it
|
||
if XParm EQ 1
|
||
inc bx
|
||
endif
|
||
if XParm EQ -1
|
||
dec bx
|
||
endif
|
||
if YParm EQ 1
|
||
inc cx
|
||
endif
|
||
if YParm EQ -1
|
||
dec cx
|
||
endif
|
||
dec ah ;at end of pattern?
|
||
jnz CheckMoreLine
|
||
mov si,di ;get back start of pattern
|
||
lodsb
|
||
mov ah,al ;reset pattern count
|
||
|
||
CheckMoreLine:
|
||
dec dx
|
||
jnz LineUpLoop
|
||
jmp LineUpEnd
|
||
endm
|
||
|
||
LineUp proc near
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push es
|
||
|
||
mov di,ax
|
||
|
||
mov ax,GRAPHICS_SEGMENT
|
||
mov es,ax
|
||
|
||
push dx ;save line length
|
||
;
|
||
; Enable writes to all planes.
|
||
;
|
||
mov dx,SC_INDEX
|
||
mov al,MAP_MASK
|
||
out dx,al
|
||
inc dx
|
||
mov al,0fh
|
||
out dx,al
|
||
;
|
||
; Select write mode 2.
|
||
;
|
||
mov dx,GC_INDEX
|
||
mov al,GRAPHICS_MODE
|
||
out dx,al
|
||
inc dx
|
||
mov al,02h
|
||
out dx,al
|
||
;
|
||
; Vector to proper routine.
|
||
;
|
||
pop dx ;get back line length
|
||
|
||
shl di,1
|
||
jmp cs:[LineUpVectors+di]
|
||
;
|
||
; Horizontal line to right.
|
||
;
|
||
LineUp0:
|
||
MLineUp 1, 0
|
||
;
|
||
; Diagonal line to upper right.
|
||
;
|
||
LineUp1:
|
||
MLineUp 1, -1
|
||
;
|
||
; Vertical line to top.
|
||
;
|
||
LineUp2:
|
||
MLineUp 0, -1
|
||
;
|
||
; Diagonal line to upper left.
|
||
;
|
||
LineUp3:
|
||
MLineUp -1, -1
|
||
;
|
||
; Horizontal line to left.
|
||
;
|
||
LineUp4:
|
||
MLineUp -1, 0
|
||
;
|
||
; Diagonal line to bottom left.
|
||
;
|
||
LineUp5:
|
||
MLineUp -1, 1
|
||
;
|
||
; Vertical line to bottom.
|
||
;
|
||
LineUp6:
|
||
MLineUp 0, 1
|
||
;
|
||
; Diagonal line to bottom right.
|
||
;
|
||
LineUp7:
|
||
MLineUp 1, 1
|
||
|
||
LineUpEnd:
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
ret
|
||
LineUp endp
|
||
;
|
||
; Draws a dot in the specified color at the specified location.
|
||
; Assumes that the VGA is in write mode 2 with writes to all planes
|
||
; enabled and that ES points to display memory.
|
||
;
|
||
; Input:
|
||
; AL = dot color
|
||
; BX = X coordinate of dot
|
||
; CX = Y coordinate of dot
|
||
; ES = display memory segment
|
||
;
|
||
; All registers preserved.
|
||
;
|
||
DotUpInColor proc near
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push di
|
||
;
|
||
; Point ES:DI to the display memory byte in which the pixel goes, with
|
||
; the bit mask set up to access that pixel within the addressed byte.
|
||
;
|
||
push ax ;preserve dot color
|
||
mov ax,SCREEN_WIDTH_IN_BYTES
|
||
mul cx ;offset of start of top scan line
|
||
mov di,ax
|
||
mov cl,bl
|
||
and cl,111b
|
||
mov dx,GC_INDEX
|
||
mov al,BIT_MASK
|
||
out dx,al
|
||
inc dx
|
||
mov al,80h
|
||
shr al,cl
|
||
out dx,al ;set the bit mask for the pixel
|
||
shr bx,1
|
||
shr bx,1
|
||
shr bx,1 ;X in bytes
|
||
add di,bx ;offset of byte pixel is in
|
||
mov al,es:[di] ;load latches
|
||
pop ax ;get back dot color
|
||
stosb ;write dot in desired color
|
||
|
||
pop di
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
ret
|
||
DotUpInColor endp
|
||
Start endp
|
||
Code ends
|
||
end Start
|