home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Boston 2
/
boston-2.iso
/
DOS
/
PROGRAM
/
PASCAL
/
VGAFONT
/
VGA_FONT.DOC
< prev
next >
Wrap
Text File
|
1993-12-01
|
24KB
|
529 lines
2/13/90
Joseph J. Tamburino
7 Christopher Rd.
Westford, MA 01886
Prodigy: NWNJ91A
CompuServe: 70033,107
Phone: 508-692-7756
Dear Fellow Programmer:
I have written some routines that I would love to share with
you. These routines allow graphics to be displayed with ordinary
EGA or VGA text modes. The routines work by modifying unused
characters to represent graphic primitives as the primitives are
being drawn. For instance, if the Line procedure was called, a
line of graphic characters would be allocated and modified so that
a line appears on the screen, just as it would with a standard
graphics mode.
These routines are still under development, so no claim is
made to ensure that they work 100%. The demonstration program has
been tested on a 256K VGA system, however the code has been
designed with the intention that EGA users might also use them.
Files Included
--------------
These files should be included with the archived version:
VGAfont.PAS: The demonstration program, written with Turbo Pascal
version 5.0
VGAfont.EXE: The compiled demonstration program.
V_FONT_U.PAS: The interface to the actual assembler routines, in
unit format.
V_FONT_U.TPU: The compiled V_FONT_U unit.
VGA_FONT.ASM: The actual font redefinition routines.
VGA_FONT.OBJ: The compiled version of VGA_FONT.ASM
VGA_FONT.DOC: This file.
Note that all of the filenames use underscores except for the
VGAfont files. The reason for this inconsistency is that Symdeb &
MapSym, the debuggers I used to debug this, do not support main
filenames containing underscores, for some very strange reason.
How to use the routines
-----------------------
Since the individual routines are clearly documented, I will
not bother to discuss all of them here. Instead, I'll just discuss
the overall use of the V_FONT_U unit.
The V_FONT_U unit stands for VGA_FONT_UNIT. None of the
filenames even hint at the possibility that the routines will
support EGA also, however they should work for EGA adapters. Since
I have not tried them on an EGA system, I cannot be sure that they
will actually work on them, however they should work on all VGAs.
The first thing that the body of your Pascal program should do
is to set the number of scan lines the program will use. The
reason for this is that on the VGA adapter, the default 400-line
screen mode displays the standard 8-bit wide characters using 9-bit
wide display fields. Since the fields are too big, an extra
vertical line is displayed to the right of all characters, except
for the designated border characters which are displayed with their
right most pixel extended to the 9th position. This setup tends to
make images appear perforated, or like venetian blinds, and thus
may not be appropriate for your needs. The 350-line & 200-line
modes solve this problem by only displaying characters at 8-bits
per character. To change to one of these modes, use the
Make8BitChars procedure with the number of scan-lines you want as
the parameter. To revert back to 9-bit display fields, call the
Make9BitChars procedure. These settings remain in effect until
they are changed back, even if the display mode is changed.
The program also must set the EGA_VGA flag to either EGA or
VGA depending on the adapter being used.
The next step is to call the FontInit procedure with two
buffers to be used with the font procedures. The first parameter
is a pointer to a 6144-byte font-table buffer, and the second is a
4096-byte screen buffer to record the screen's contents. See the
demonstration program for details.
Once done, use the graphics primitives in the same fashion you
are probably used to doing. For instance, to draw a line from the
top-left corner to the bottom-right in blue, use the statement:
Line(0,0,MaxX,MaxY,1). To draw a horizontal line at the bottom of
the screen using green, use Hlin(0,MaxY,MaxX,2).
Each time a graphics primitive is executed, the variable
TotalUsed is updated with the total number of graphics characters
allocated as of the time it is being sampled. It is important to
keep track of this variable, because if it reaches 384 (the maximum
# of characters that can be allocated), no more new characters can
be allocated. Keep in mind that if you draw an image directly onto
an existing image (with no overlap), no new characters will be
allocated, since they have already been allocated. Also keep in
mind that if you erase an area using color 0, any characters that
end up becoming zero will be de-allocated, and substituted with the
space character. This happens with any graphics primitive you use.
To clear and deallocate all of the characters being used for
graphics, use the ClearChars procedure. As an argument, include
the same buffer-area you have used previously with FontInit or
2
GetScrn to restore the text-screen to the desired format. Again,
see the demonstration program for clear examples.
If you intend to do animation, the Freeze & UnFreeze
procedures will undoubtedly be of help. Freeze copies the current
page 0 image to another page, and displays that page. Meanwhile,
all graphics functions still effect page 0 (but not the display).
UnFreeze flips back to page 0 to display the changes made during
the time the image was "frozen". These procedures are necessary
since the act of constantly updating & changing the character set
and screen produces a substantial amount of flicker.
Unfortunately, the WriteFont procedure (used by ClearChars, and all
other graphics primitives) always resets the current video page to
0, resulting in a premature unfreeze of the display. So the freeze
procedure really must be used twice: once before, and once after a
graphics primitive is executed. Even then, the flickering is not
completely disabled. The UnFreeze procedure can be used at any
time; in fact, it doesn't have to be used at all since the
graphics primitives automatically do the equivalent of UnFreeze.
Once again, see the demonstration program for examples.
You may wonder why the WriteFont procedure changes the video
page, and what can be done about it since the change is so
inconvenient in an animation sequence. The WriteFont procedure
simply uses function 11h of INT 10h to copy the font information to
the adapter's font memory. Why INT 10h changes the video mode is
beyond me. However it is, of course, possible to bypass the BIOS
and copy the font table directly to the adapter's memory yourself.
I tried this, and two problems occurred. First of all, I couldn't
get all of the characters to copy for some reason. I'm sure this
was my own error, but I couldn't see anything wrong with my coding.
Secondly, the font-writing seems to produce terrible hardware-
generated snow on the screen. Waiting for vertical retrace
decreases the amount of flicker, but by no means does it eliminates
it. Since I could never get these problems resolved, I had to
continue using the BIOS. If anyone knows how to bypass the BIOS in
order to not tamper with the video-page setting, and yet remain
flicker-free, let me know -- please!
The Ellipse procedure, by the way, supports solid fills, as
well as outline fills. To achieve solid fills, set bit 7 of the
color byte to high. (This bit is stripped before the ellipse is
displayed).
Speed
-----
As you will note, my routines are not very fast. This is
because every single routine calls the main Pset routine to plot
each individual point separately. Although modular, this method is
very slow. A better way to program graphics routines is to have
the routines keep track of the bit position and character number
itself, and decrement and increment when as needed. While this is
3
relatively easy for regular graphics modes, there would be a great
deal of work involved when doing this for text-mode. However, you
are encouraged to try and speed the routines up yourself. My
suggestion to you is to speed the Hlin2 procedure up first, since
this procedure is used by Box, OpenBox, and Ellipse. Line & Vlin
should probably be improved next. Another suggestion would be to
design useful Get & Put procedures. Please let me know of any
improvements you make, so I can include both the code and your name
in future revisions of the code.
Attributes and 512-character fonts
----------------------------------
In order to have 256 character fonts (the standard), it is
required to have eight bits of information. These eight bits forms
what is known as the IBM ASCII code (the smallest number of bits a
computer can use and still remain ASCII compatible is six. This
provides 64 possible symbols and does not allow lowercase). If I
were to program these routines using only the standard 256-
character font, I would have to decide which of those characters I
am able to "give up" for graphics purposes. If it were me, I would
use the upper 128 characters, those used by IBM to produce borders
and things. As it turns out, 128 characters is not sufficient for
most applications, because it doesn't allow very much graphic
information to be displayed at once (although the actual amount of
information possible varies considerably with the way the images
are displayed).
By using 512-character fonts, it is possible to have the
original 128 plus 256 new characters for a total of 384 characters.
This number is still too small, but is the most characters a VGA
card can produce at once. The problem, however, is how to refer to
the new nine-bit character code. The 80x25 color IBM screen (mode
3) only provides eight bits for the character code, and eight for
the attribute code. Obviously, to use 512-character sets, it is
necessary to "steal" one of the attribute bits. The designers of
the VGA decided to use the high-order bit of the forground
attribute field (bit 3, or the intensity bit). Personally, if I
had the choice, I would have used bit 7, the high bit of the
background field. This is because, traditionally, that bit was
sometimes reserved for blinking, so people became used to only
having 8 background color choices.
But they choose to alter the forground. This leads to the
next question: So what color will 7 represent? How about 15? The
question is: How is the 4'th bit represented on the screen? The
answer is: Normally the bit is represented in the usual fashion.
This means that if you had an image comprised of some low-order
characters, and some high-order characters, and all characters were
displayed with attribute 7, then some of the image would appear
dark-white, and some of it would appear light-white. The same goes
for all the other colors.
4
To get around this, it is possible to program the EVGA card to
mask this bit in such a way to only display the low-intensity
colors. And this is what the MaskColors procedure does. By the
way, the Make512chars procedure sets up 512-character mode. Once
again, find the occurrence of MaskColors in the demo program and
observe how it uses the procedure (it's in the EllipseDemo
procedure). The Make512chars procedure is used during the
initialization of the unit, and is not something you have to worry
about -- the unit will always use 512-character fonts. Please note
that although you can only have 8 colors in this setup, you are not
required to use the standard 8 colors. For instance, the VGA
allows you to use any 8 of the available 256K colors it has
available, and the EGA will allow any 8 of 64 colors.
Global Constants and Variables
------------------------------
The V_FONT_U unit provides the following global constants and
variables for use in your main program:
EGA,VGA: For use with the EGA_VGA boolean flag to represent
the type of adapter being used. I.e., EGA_VGA:=EGA
will setup for an EGA adapter. Note: for SuperEGA,
the VGA mode may work better.
LargestChar: The largest character code (511).
SmallestChar: The smallest character code (128).
FontSize: The size for 384 characters at 16 bytes (points)
each (1800h bytes).
MaxX,MaxY: The maximum coordinate possible (variables that
depend on the # of lines. MaxX is always 639).
EGA_VGA: Boolean variable that defaults to VGA (see above).
TotalUsed: Variable that contains the number of characters that
are currently allocated and used by V_FONT_U. This
variable will decrease only if a black (attribute 0)
image is drawn that completely covers one or more
character cells or if the ClearChars procedure is
called.
Using and Improving the Code
----------------------------
Using the code, as you can see by observing the demo, is
fairly straightforward. To use graphics in text mode, the
following actions must be performed by the application:
5
1) Set the number of displayable pixels per character cell with
the Make8BitChars or the Make9BitChars procedures. Note that 9
bit characters are made up of only 8 pixels, although the VGA
card will display 9. The Make8BitChars procedure contains a
parameter which defines the number of lines to display (350 or
200). The Make9BitChars procedure automatically uses 400
lines.
2) Select 80x25 color or monochrome text mode (mode 2 or 3).
3) Initialize the V_FONT_U init by calling FontInit with two
parameters: The address of a font buffer from 1 to FontSize,
and the address of the screen buffer from 1 to 4096. Note that
ClearChars will reset the screen to look as it does when this
procedure is called. To change the way the screen looks to
ClearChars later on, use the GetScrn procedure.
4) Use standard text routines such as Write, WriteLn, GotoXY,
etc., as you normally do, and also take advantage of the new
graphics primitives.
5) Keep track of TotalUsed to make sure that it doesn't equal 384.
If it does, no more graphics routines will take effect if they
need to define new cells.
That's all there really is to this in general. To improve the
code, many things can be done. For starters, there is no way of
preventing duplicate characters from being generated. For
instance, a call to Hlin might produce a series of similar solid
line characters. This is a complete waste of space. However, to
change this would require a huge slow down of processor time if the
change is to occur dynamically. To see this, imagine what would
happen if we did produce a horizontal line using only one
character. What would happen if we then decided to draw a vertical
line through the middle, intersecting the previous line? The
intersection would produce a "+" character. And this character
would suddenly appear duplicated throughout every instance of the
original solid line character. In effect, the line would suddenly
look something like: |
+++++++++++++++++++++
|
Although the line would really not be perforated. To get
around this problem, a table would be required to see if a
character is duplicated in another place BEFORE changing it. If it
is, a new character would be allocated, and put into position. The
actual point-plotting procedure would have to be expanded in a
different way, also. In stead of blindly putting down character
cells, it would have to check and see if there was anything else
there. Still, this is a feasible change.
Another method would be to define one single procedure called
"Consolidate" or something to that effect. It's job would be to
6
look at every character and see what can be duplicated. Instead of
doing it dynamically, it would be more of a periodic type
situation. If there are any plans to be able to plot points AFTER
the consolidate procedure has executed, a table would be required
to store all duplicated characters, and further Pset operations
would have to define new characters if one of those has been
encountered (just like the last example).
Another possible change would be to abandon the top-down
design that all the graphics primitives use; they all call the
single and lengthy Pset procedure. As you'll see, this would take
quite a lot of work. In the end, who knows whether it will be
worth it or not. If you're not quite sure what I am referring to,
take this simple example: The 320x200x256 color mode (13h) is a
simple array of contiguous bytes. Therefore, here are two
assembly-language procedure capable of drawing a horizontal line
from x1 to x2 at the vertical line y1:
mov cx,x2
sub cx,x1
inc cx
Looph:push x1 ; Provide parameter x1
push y1 ; Provide parameter y1
call Pset
inc x1
loop Looph
(Note that the pixel color is ignored). You'll find a very
similar construct in the Hlin procedure provided in VGA_FONT.ASM.
Here is another method for the 320x200x256 mode:
mov ax,320
mul y1
add ax,x1
mov di,ax
mov cx,x2
sub cx,x1
inc cx
rep stosb
Of course, this is an incomplete example; the segment
register has not been set, and the direction flag has not been
cleared. But notice the difference between the two subroutines.
In the first routine, a large amount of instructions had to be
performed for each and every pixel in the line. For the second,
the whole line was drawn using only one instruction (actually a
prefix and a complete instruction). Obviously the second will run
faster. Although it is non-modular, it is the better choice to use
in most applications. If you examine the code for Pset in
VGA_FONT.ASM, you'll note that in the course of execution, several
other lengthy procedures also get called, which is why the routines
execute so slowly. Nevertheless, it would be impossible to code an
Hlin routine for text mode the same way I did for mode 13h.
Chances are, however, that it could be made faster via successive
7
shifting of the next cell pixel position, instead of calling Pset
for every single pixel.
Actually, the longest part of the Pset routine is the call to
the BIOS to update the character fonts. To circumvent this,
procedures that use Pset actually use Pset2 instead. Pset2 has the
same function as Pset except that the character font is not
updated. Obviously, this means that such a graphics primitive must
do this itself at the end. Likewise, Hlin also has a counterpart
called Hlin2 which does not update the font, thereby enabling a
procedure such as box to save that operation for last.
Other changes: Please see the V_FONT_U.PAS file for more
update suggestions, and feel free to make changes as you feel are
appropriate. Please keep in touch with me so I know what kinds of
wonderful things are happening to my code.
Royalties
---------
Unless I feel that you have made a significant ["significant"
is subject to be defined in accordance to my own discretion]
improvement to this package, there is a $10.00 fee to use any or
all of this code in your own program, if you plan to release the
program to other individuals, companies, or fellow employees. This
fee applies regardless of whether you sell the program for money,
or just give it away free. Note that this code is copyright (c)
February 1990, by Joseph J. Tamburino.
If you have made a significant improvement, you will be
entitled to increase the fee as long as $10.00 still goes to Joseph
J. Tamburino and as long as I have given you permission to do so.
Send all correspondence regarding VGA_FONT to:
Joseph J. Tamburino
7 Christopher Rd.
Westford, MA 01886
Phone: 508-692-7756
Prodigy accnt #: NWNJ91A
CompuServe accnt #: 70033,107
Above all, enjoy the routines!
8