330 lines
15 KiB
HTML
330 lines
15 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: Saving Screens and Other VGA Mysteries</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=29//-->
|
|
<!--PAGES=550-555//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="29-03.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="29-05.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
</P>
|
|
<P>How does one go about setting the palette registers? Well, it’s certainly possible to set the palette registers directly by addressing them at registers 0 through 0FH of the Attribute Controller. However, setting the palette registers is a bit tricky—bit 5 of the Attribute Controller Index register must be 0 while the palette registers are written to, and glitches can occur if the updating doesn’t take place during the blanking interval—and besides, it turns out that there’s no need at all to go straight to the hardware on this one. Conveniently, the EGA BIOS provides us with video function 10H, which supports setting either any one palette register or all 16 palette registers (and the overscan register as well) with a single video interrupt.
|
|
</P>
|
|
<P>Video function 10H is invoked by performing an <B>INT</B> 10H with AH set to 10H. If AL is 0 (subfunction 0), then BL contains the number of the palette register to set, and BH contains the value to set that register to. If AL is 1 (subfunction 1), then BH contains the value to set the overscan (border) color to. Finally, if AL is 2 (subfunction 2), then ES:DX points to a 17-byte array containing the values to set palette registers 0-15 and the overscan register to. (For completeness, although it’s unrelated to the palette registers, there is one more subfunction of video function 10H. If AL = 3 (subfunction 3), bit 0 of BL is set to 1 to cause bit 7 of text attributes to select blinking, or set to 0 to cause bit 7 of text attributes to select highreverse video.)</P>
|
|
<P><A NAME="Fig3"><!-- </A><A HREF="javascript:displayWindow('images/29-03.jpg',407,152 )"> --><IMG SRC="images/29-03.jpg"><BR><!-- </A>
|
|
<BR><A HREF="javascript:displayWindow('images/29-03.jpg',407,152)"> --><FONT COLOR="#000077"><B>Figure 29.3</B></FONT></A> <I>Bit organization within a palette register.</I>
|
|
</P>
|
|
<P>Listing 29.3 uses video function 10H, subfunction 2 to step through all 64 possible colors. This is accomplished by putting up 16 color bars, one for each of the 16 possible 4-bit pixel values, then changing the mapping provided by the palette registers to select a different group of 16 colors from the set of 64 each time a key is pressed. Initially, colors 0-15 are displayed, then 1-16, then 2-17, and so on up to color 3FH wrapping around to colors 0-14, and finally back to colors 0-15. (By the way, at mode set time the 16 palette registers are not set to colors 0-15, but rather to 0H, 1H, 2H, H, 4H, 5H, 14H, 7H, 38H, 39H, 3AH, 3BH, 3CH, 3DH, 3EH, and 3FH, respectively. Bits 6, 5, and 4—secondary red, green, and blue—are all set to 1 in palette registers 8-15 in order to produce high-intensity colors. Palette register 6 is set to 14H to produce brown, rather than the yellow that the expected value of 6H would produce.)
|
|
</P>
|
|
<P>When you run Listing 29.3, you’ll see that the whole screen changes color as each new color set is selected. This occurs because most of the pixels on the screen have a value of 0, selecting the background color stored in palette register 0, and we’re reprogramming palette register 0 right along with the other 15 palette registers.</P>
|
|
<P>It’s important to understand that in Listing 29.3 the contents of display memory are never changed after initialization. The only change is the mapping from the 4-bit pixel data coming out of display memory to the 6-bit data going to the monitor. For this reason, it’s technically inaccurate to speak of bits in display memory as representing colors; more accurately, they represent attributes in the range 0-15, which are mapped to colors 0-3FH by the palette registers.</P>
|
|
<P><B>LISTING 29.3 L29-3.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; Program to illustrate the color mapping capabilities of the
|
|
; EGA’s palette registers.
|
|
;
|
|
VGA_SEGMENT equ 0a000h
|
|
SC_INDEX equ 3c4h ;Sequence Controller Index register
|
|
MAP_MASK equ 2 ;Map Mask register index in SC
|
|
BAR_HEIGHT equ 14 ;height of each bar
|
|
TOP_BAR equ BAR_HEIGHT*6 ;start the bars down a bit to
|
|
; leave room for text
|
|
;
|
|
stack segment para stack ‘STACK’
|
|
db 512 dup (?)
|
|
stack ends
|
|
;
|
|
Data segment word ‘DATA’
|
|
KeyMsg db ‘Press any key to see the next color set. ’
|
|
db ‘There are 64 color sets in all.’
|
|
db 0dh, 0ah, 0ah, 0ah, 0ah
|
|
db 13 dup (‘ ’), ‘Attribute’
|
|
db 38 dup (‘ ’), ‘Color$’
|
|
;
|
|
; Used to label the attributes of the color bars.
|
|
;
|
|
AttributeNumbers label byte
|
|
x= 0
|
|
rept 16
|
|
if x lt 10
|
|
db ‘0’, x+‘0’, ‘h’, 0ah, 8, 8, 8
|
|
else
|
|
db ‘0’, x+‘A’-10, ‘h’, 0ah, 8, 8, 8
|
|
endif
|
|
x= x+1
|
|
endm
|
|
db ‘$’
|
|
;
|
|
; Used to label the colors of the color bars. (Color values are
|
|
; filled in on the fly.)
|
|
;
|
|
ColorNumberslabelbyte
|
|
rept 16
|
|
db ‘000h’, 0ah, 8, 8, 8, 8
|
|
endm
|
|
COLOR_ENTRY_LENGTHequ($-ColorNumbers)/16
|
|
db ‘$’
|
|
;
|
|
CurrentColordb?
|
|
;
|
|
; Space for the array of 16 colors we’ll pass to the BIOS, plus
|
|
; an overscan setting of black.
|
|
;
|
|
ColorTable db 16 dup (?), 0
|
|
Data ends
|
|
;
|
|
Code segment
|
|
assume cs:Code, ds:Data
|
|
Start procnear
|
|
cld
|
|
mov ax,Data
|
|
mov ds,ax
|
|
;
|
|
; Go to hi-res graphics mode.
|
|
;
|
|
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
|
|
; hi-res graphics mode
|
|
int 10h ;BIOS video interrupt
|
|
;
|
|
; Put up relevant text.
|
|
;
|
|
mov ah,9 ;DOS print string function
|
|
mov dx,offset KeyMsg
|
|
int 21h
|
|
;
|
|
; Put up the color bars, one in each of the 16 possible pixel values
|
|
; (which we’ll call attributes).
|
|
;
|
|
mov cx,16 ;we’ll put up 16 color bars
|
|
sub al,al ;start with attribute 0
|
|
BarLoop:
|
|
push ax
|
|
push cx
|
|
call BarUp
|
|
pop cx
|
|
pop ax
|
|
inc ax ;select the next attribute
|
|
loop BarLoop
|
|
;
|
|
; Put up the attribute labels.
|
|
;
|
|
mov ah,2 ;video interrupt set cursor position function
|
|
sub bh,bh ;page 0
|
|
mov dh,TOP_BAR/14 ;counting in character rows, match to
|
|
; top of first bar, counting in
|
|
; scan lines
|
|
mov dl,16 ;just to left of bars
|
|
int 10h
|
|
mov ah,9 ;DOS print string function
|
|
mov dx,offset AttributeNumbers
|
|
int 21h
|
|
;
|
|
; Loop through the color set, one new setting per keypress.
|
|
;
|
|
mov [CurrentColor],0 ;start with color zero
|
|
ColorLoop:
|
|
;
|
|
; Set the palette registers to the current color set, consisting
|
|
; of the current color mapped to attribute 0, current color + 1
|
|
; mapped to attribute 1, and so on.
|
|
;
|
|
mov al,[CurrentColor]
|
|
mov bx,offset ColorTable
|
|
mov cx,16 ;we have 16 colors to set
|
|
PaletteSetLoop:
|
|
and al,3fh ;limit to 6-bit color values
|
|
mov [bx],al ;build the 16-color table used for setting
|
|
inc bx ; the palette registers
|
|
inc ax
|
|
loop PaletteSetLoop
|
|
mov ah,10h ;video interrupt palette function
|
|
mov al,2 ;subfunction to set all 16 palette registers
|
|
; and overscan at once
|
|
mov dx,offset ColorTable
|
|
push ds
|
|
pop es ;ES:DX points to the color table
|
|
int 10h ;invoke the video interrupt to set the palette
|
|
;
|
|
; Put up the color numbers, so we can see how attributes map
|
|
; to color values, and so we can see how each color # looks
|
|
; (at least on this particular screen).
|
|
;
|
|
call ColorNumbersUp
|
|
;
|
|
; Wait for a keypress, so they can see this color set.
|
|
;
|
|
WaitKey:
|
|
mov ah,8 ;DOS input without echo function
|
|
int 21h
|
|
;
|
|
; Advance to the next color set.
|
|
;
|
|
mov al,[CurrentColor]
|
|
inc ax
|
|
mov [CurrentColor],al
|
|
cmp al,64
|
|
jbe ColorLoop
|
|
;
|
|
; Restore text mode.
|
|
;
|
|
mov ax,3
|
|
int 10h
|
|
;
|
|
; Done.
|
|
;
|
|
Done:
|
|
mov ah,4ch ;DOS terminate function
|
|
int 21h
|
|
;
|
|
; Puts up a bar consisting of the specified attribute (pixel value),
|
|
; at a vertical position corresponding to the attribute.
|
|
;
|
|
; Input: AL = attribute
|
|
;
|
|
BarUp proc near
|
|
mov dx,SC_INDEX
|
|
mov ah,al
|
|
mov al,MAP_MASK
|
|
out dx,al
|
|
inc dx
|
|
mov al,ah
|
|
out dx,al ;set the Map Mask register to produce
|
|
; the desired color
|
|
mov ah,BAR_HEIGHT
|
|
mul ah ;row of top of bar
|
|
add ax,TOP_BAR ;start a few lines down to leave room for
|
|
; text
|
|
mov dx,80 ;rows are 80 bytes long
|
|
mul dx ;offset in bytes of start of scan line bar
|
|
; starts on
|
|
add ax,20 ;offset in bytes of upper left corner of bar
|
|
mov di,ax
|
|
mov ax,VGA_SEGMENT
|
|
mov es,ax ;ES:DI points to offset of upper left
|
|
; corner of bar
|
|
mov dx,BAR_HEIGHT
|
|
mov al,0ffh
|
|
BarLineLoop:
|
|
mov cx,40 ;make the bars 40 wide
|
|
rep stosb ;do one scan line of the bar
|
|
add di,40 ;point to the start of the next scan line
|
|
; of the bar
|
|
dec dx
|
|
jnz BarLineLoop
|
|
ret
|
|
BarUp endp
|
|
;
|
|
; Converts AL to a hex digit in the range 0-F.
|
|
;
|
|
BinToHexDigit proc near
|
|
cmp al,9
|
|
ja IsHex
|
|
add al,‘0’
|
|
ret
|
|
IsHex:
|
|
add al,‘A’-10
|
|
ret
|
|
BinToHexDigit endp
|
|
;
|
|
; Displays the color values generated by the color bars given the
|
|
; current palette register settings off to the right of the color
|
|
; bars.
|
|
;
|
|
ColorNumbersUp proc near
|
|
mov ah,2 ;video interrupt set cursor position function
|
|
sub bh,bh ;page 0
|
|
mov dh,TOP_BAR/14 ;counting in character rows, match to
|
|
; top of first bar, counting in
|
|
; scan lines
|
|
mov dl,20+40+1 ;just to right of bars
|
|
int 10h
|
|
mov al,[CurrentColor] ;start with the current color
|
|
mov bx,offset ColorNumbers+1
|
|
;build color number text string on the fly
|
|
mov cx,16 ;we’ve got 16 colors to do
|
|
ColorNumberLoop:
|
|
pus hax;save the color #
|
|
and al,3fh;limit to 6-bit color values
|
|
shr al,1
|
|
shr al,1
|
|
shr al,1
|
|
shr al,1 ;isolate the high nibble of the color #
|
|
call BinToHexDigit ;convert the high color # nibble
|
|
mov [bx],al ; and put it into the text
|
|
pop ax ;get back the color #
|
|
push ax ;save the color #
|
|
and al,0fh ;isolate the low color # nibble
|
|
call BinToHexDigit ;convert the low nibble of the
|
|
; color # to ASCII
|
|
mov [bx+1],al ; and put it into the text
|
|
add bx,COLOR_ENTRY_LENGTH ;point to the next entry
|
|
pop ax ;get back the color #
|
|
inc ax ;next color #
|
|
loop ColorNumberLoop
|
|
mov ah,9 ;DOS print string function
|
|
mov dx,offset ColorNumbers
|
|
int 21h ;put up the attribute numbers
|
|
ret
|
|
ColorNumbersUpendp
|
|
;
|
|
Start endp
|
|
Code ends
|
|
end Start
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="29-03.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="29-05.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 -->
|
|
|
|
|