home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
-
- 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
-
-
-
-
-