246 lines
13 KiB
HTML
246 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: Color Modeling in 256-Color 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=55//-->
|
|
<!--PAGES=1040-1044//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="55-03.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="56-01.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P>This is where it gets a little complicated. In write mode 3 (which incidentally is not available on the EGA), each byte value that the CPU writes to the VGA does not get written to display memory. Instead, it turns into the bit mask. (Actually, it’s ANDed with the Bit Mask register, and the result becomes the bit mask, but we’ll leave the Bit Mask register set to 0xFF, so the CPU value will become the bit mask.) The bit mask selects, on a bit-by-bit basis, between the data in the latches for each plane (the previously loaded background color, in this case) and the foreground color. Where does the foreground color come from, if not from the CPU? From the Set/Reset register, as shown in Figure 55.3. Thus, each byte written by the CPU (font data, presumably) selects foreground or background color for each of eight pixels, all done with a single write to display memory.
|
|
</P>
|
|
<P><A NAME="Fig3"><!-- </A><A HREF="javascript:displayWindow('images/55-03.jpg',407,375 )"> --><IMG SRC="images/55-03.jpg"><BR><!-- </A>
|
|
<BR><A HREF="javascript:displayWindow('images/55-03.jpg',407,375)"> --><FONT COLOR="#000077"><B>Figure 55.3</B></FONT></A> <I>The data path in write mode 3.</I>
|
|
</P>
|
|
<P>I know this sounds pretty esoteric, but think of it this way: The latches hold the background color in a form suitable for writing eight background pixels (one full byte) at a pop. Write mode 3 allows each CPU byte to punch holes in the background color provided by the latches, holes through which the foreground color from the Set/Reset register can flow. The result is that a single write draws exactly the combination of foreground and background pixels described by each font byte written by the CPU. It may help to look at Listing 55.4, which shows The BitMan’s technique in action. And yes, this technique is absolutely worth the trouble; it’s about three times faster than the fill-then-draw approach described above, and about twice as fast as transparent text. So far as I know, there is no faster way to draw text on a VGA.
|
|
</P>
|
|
<P>It’s important to note that the BitMan’s technique only works on full bytes of display memory. There’s no way to clip to finer precision; the background color will inevitably flood all of the eight destination pixels that aren’t selected as foreground pixels. This makes The BitMan’s technique most suitable for monospaced fonts with characters that are multiples of eight pixels in width, and for drawing to byte-aligned addresses; the technique can be used in other situations, but is considerably more difficult to apply.</P>
|
|
<P><B>LISTING 55.4 L55-4.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; Demonstrates drawing solid text on the VGA, using the BitMan’s write mode
|
|
; 3-based, one-pass technique.
|
|
|
|
CHAR_HEIGHT equ 8 ;# of scan lines per character (must be <256)
|
|
SCREEN_HEIGHT equ 480 ;# of scan lines per screen
|
|
SCREEN_SEGMENT equ 0a000h ;where screen memory is
|
|
FG_COLOR equ 14 ;text color
|
|
BG_COLOR equ 1 ;background box color
|
|
GC_INDEX equ 3ceh ;Graphics Controller (GC) Index reg I/O port
|
|
SET_RESET equ 0 ;Set/Reset register index in GC
|
|
G_MODE equ 5 ;Graphics Mode register index in GC
|
|
BIT_MASK equ 8 ;Bit Mask register index in GC
|
|
|
|
.model small
|
|
.stack 200h
|
|
.data
|
|
Line dw ? ;current line #
|
|
CharHeight dw ? ;# of scan lines in each character (must be <256)
|
|
MaxLines dw ? ;max # of scan lines of text that will fit on screen
|
|
LineWidthBytes dw ? ;offset from one scan line to the next
|
|
FontPtr dd ? ;pointer to font with which to draw
|
|
SampleString label byte
|
|
db ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’
|
|
db ‘abcdefghijklmnopqrstuvwxyz’
|
|
db ‘0123456789!@#$%^&*(),<.>/?;:’,0
|
|
|
|
.code
|
|
start:
|
|
mov ax,@data
|
|
mov ds,ax
|
|
|
|
mov ax,12h
|
|
int 10h ;select 640x480 16-color mode
|
|
|
|
mov ah,11h ;BIOS character generator function
|
|
mov al,30h ;BIOS get font pointer subfunction
|
|
mov bh,3 ;get 8x8 ROM font subsubfunction
|
|
int 10h ;get the pointer to the BIOS 8x8 font
|
|
mov word ptr [FontPtr],bp
|
|
mov word ptr [FontPtr+2],es
|
|
|
|
mov bx,CHAR_HEIGHT
|
|
mov [CharHeight],bx ;# of scan lines per character
|
|
mov ax,SCREEN_HEIGHT
|
|
sub dx,dx
|
|
div bx
|
|
mul bx ;max # of full scan lines of text that
|
|
mov [MaxLines],ax ; will fit on the screen
|
|
|
|
mov ah,0fh ;BIOS video status function
|
|
int 10h ;get # of columns (bytes) per row
|
|
mov al,ah ;convert byte columns variable in
|
|
sub ah,ah ; AH to word in AX
|
|
mov [LineWidthBytes],ax ;width of scan line in bytes
|
|
;now draw the text
|
|
sub bx,bx
|
|
mov [Line],bx ;start at scan line 0
|
|
LineLoop:
|
|
sub ax,ax ;start at column 0; must be a multiple of 8
|
|
mov ch,FG_COLOR ;color in which to draw text
|
|
mov cl,BG_COLOR ;color in which to draw background box
|
|
mov si,offset SampleString ;text to draw
|
|
call DrawTextString ;draw the sample text
|
|
mov bx,[Line]
|
|
add bx,[CharHeight] ;# of next scan line to draw on
|
|
mov [Line],bx
|
|
cmp bx,[MaxLines] ;done yet?
|
|
jb LineLoop ;not yet
|
|
|
|
mov ah,7
|
|
int 21h ;wait for a key press, without echo
|
|
|
|
mov ax,03h
|
|
int 10h ;back to text mode
|
|
|
|
mov ah,4ch
|
|
int 21h ;exit to DOS
|
|
|
|
; Draws a text string.
|
|
; Input: AX = X coordinate at which to draw upper-left corner of first char
|
|
; BX = Y coordinate at which to draw upper-left corner of first char
|
|
; CH = foreground (text) color
|
|
; CL = background (box) color
|
|
; DS:SI = pointer to string to draw, zero terminated
|
|
; CharHeight must be set to the height of each character
|
|
; FontPtr must be set to the font with which to draw
|
|
; LineWidthBytes must be set to the scan line width in bytes
|
|
; Don’t count on any registers other than DS, SS, and SP being preserved.
|
|
; The X coordinate is truncated to a multiple of 8. Characters are
|
|
; assumed to be 8 pixels wide.
|
|
align 2
|
|
DrawTextString proc near
|
|
cld
|
|
shr ax,1 ;byte address of starting X within scan line
|
|
shr ax,1
|
|
shr ax,1
|
|
mov di,ax
|
|
mov ax,[LineWidthBytes]
|
|
mul bx ; start offset of initial scan line
|
|
add di,ax ;start offset of initial byte
|
|
mov ax,SCREEN_SEGMENT
|
|
mov es,ax ;ES:DI = offset of initial character’s
|
|
; first scan line
|
|
;set up the VGA’s hardware so that we can
|
|
; fill the latches with the background color
|
|
mov dx,GC_INDEX
|
|
mov ax,(0ffh SHL 8) + BIT_MASK
|
|
out dx,ax ;set Bit Mask register to 0xFF (that’s the
|
|
; default, but I’m doing this just to make sure
|
|
; you understand that Bit Mask register and
|
|
; CPU data are ANDed in write mode 3)
|
|
mov ax,(003h SHL 8) + G_MODE
|
|
out dx,ax ;select write mode 3
|
|
mov ah,cl ;background color
|
|
mov al,SET_RESET
|
|
out dx,ax ;set the drawing color to background color
|
|
mov byte ptr es:[0ffffh],0ffh
|
|
;write 8 pixels of the background
|
|
; color to unused off-screen memory
|
|
mov cl,es:[0ffffh] ;read the background color back into the
|
|
; latches; the latches are now filled with
|
|
; the background color. The value in CL
|
|
; doesn’t matter, we just needed a target
|
|
; for the read, so we could load the latches
|
|
mov ah,ch ;foreground color
|
|
out dx,ax ;set the Set/Reset (drawing) color to the
|
|
; foreground color
|
|
;we’re ready to draw!
|
|
DrawTextLoop:
|
|
lodsb ;next character to draw
|
|
and al,al ;end of string?
|
|
jz DrawTextDone ;yes
|
|
push ds ;remember string’s segment
|
|
push si ;remember offset of next character in string
|
|
push di ;remember drawing offset
|
|
;load these variables before we wipe out DS
|
|
mov dx,[LineWidthBytes] ;offset from one line to next
|
|
dec dx ;compensate for STOSB
|
|
mov cx,[CharHeight];
|
|
mul cl ;offset of character in font table
|
|
lds si,[FontPtr] ;point to font table
|
|
add si,ax ;point to start of character to draw
|
|
;the following loop should be unrolled for
|
|
; maximum performance!
|
|
DrawCharLoop: ;draw all lines of the character
|
|
mov sb ;getthe next byte of the character and draw
|
|
; character; data is ANDed with Bit Mask
|
|
; register to become bit mask, and selects
|
|
; between latch (containing the background
|
|
; color) and Set/Reset register (containing
|
|
; foreground color)
|
|
add di,dx ;point to next line of destination
|
|
loop DrawCharLoop
|
|
|
|
pop di ;retrieve initial drawing offset
|
|
inc di ;drawing offset for next char
|
|
pop si ;retrieve offset of next character in string
|
|
pop ds ;retrieve string’s segment
|
|
jmp DrawTextLoop ;draw next character, if any
|
|
|
|
align2
|
|
DrawTextDone: ;restore the Graphics Mode register to its
|
|
; default state of write mode 0
|
|
mov dx,GC_INDEX
|
|
mov ax,(000h SHL 8) + G_MODE
|
|
out dx,ax ;select write mode 0
|
|
ret
|
|
DrawTextString endp
|
|
end start
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="55-03.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="56-01.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 -->
|
|
|
|
|