402 lines
13 KiB
HTML
402 lines
13 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<META name=vsisbn content="1576101746">
|
|
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
|
|
<META name=vsauthor content="Michael Abrash">
|
|
<META name=vspublisher content="The Coriolis Group">
|
|
<META name=vspubdate content="07/01/97">
|
|
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Yet Another VGA Write Mode</TITLE>
|
|
|
|
<!-- HEADER -->
|
|
<!-- Empty Reference Subhead -->
|
|
|
|
<!--ISBN=1576101746//-->
|
|
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
|
|
<!--AUTHOR=Michael Abrash//-->
|
|
<!--PUBLISHER=The Coriolis Group, Inc.//-->
|
|
<!--CHAPTER=27//-->
|
|
<!--PAGES=508-515//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="27-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="27-04.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P>“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.
|
|
</P>
|
|
<TABLE WIDTH="100%"><TD WIDTH="5%" VALIGN="TOP"><IMG SRC="images/27-02i.jpg"><TD WIDTH="95%"><SMALL><I>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.</I></SMALL>
|
|
</TABLE>
|
|
<H4 ALIGN="LEFT"><A NAME="Heading6"></A><FONT COLOR="#000077">Drawing Color-Patterned Lines Using Write Mode 2</FONT></H4>
|
|
<P>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 <B>OUT</B>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 <B>OUT</B>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.</P>
|
|
<P>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.</P>
|
|
<P><B>LISTING 27.2 L27-2.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; 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 (640×350)
|
|
;
|
|
; 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
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="27-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="27-04.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
|
|
<hr width="90%" size="1" noshade>
|
|
<div align="center">
|
|
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book © 2001 Michael Abrash</font>
|
|
</div>
|
|
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
|
|
<!-- reference_subfoot = footer -->
|
|
<!-- reference_footer = subfoot -->
|
|
|
|
<!-- BEGIN SUB FOOTER -->
|
|
</BODY>
|
|
</HTML>
|
|
|
|
<!-- END FOOTER -->
|
|
|
|
|