home *** CD-ROM | disk | FTP | other *** search
- *PROFESSIONAL GEM*
- By Tim Oren
- Column #9 - VDI Graphics: Lines and Solids
-
- This issue of ST PRO GEM is the first in a series of two
- which will explore the fundamentals of VDI graphics output. In
- this installment, we will take a look at the commands necessary to
- output simple graphics such as lines, squares and circles as well
- as more complex figures such as polygons. The following episode
- will take a first look at graphics text output, with an emphasis
- on ways to optimize its drawing speed. It will also include
- another installment of ONLINE Feedback. As usual, there is a
- download with this column. You should find it under the name
- GEMCL9.C in DL3 of ATARI16 (PCS-58).
-
- A BIT OF HISTORY
-
- One of the reasons that the VDI can be confusing is that
- drawing anything at all, even a simple line, can involve setting
- around four different VDI parameters before making the draw call!
- (Given the state of the GEM documents, just FINDING them can be
- fun!) Looking backwards a bit sheds some light on why the VDI is
- structured this way, and also gives us a framework for organizing
- a discussion of graphics output.
-
- The GEM VDI closely follows the so-called GKS standard, which
- defines capabilities and calling sequences for a standardized
- graphic input/output system. GKS is itself an evolution from an
- early system called "Core". Both of these standards were born in
- the days when pen plotters, vectored graphics displays, and
- minicomputers were the latest items. So, if you wonder why
- setting the drawing pen color is a separate command, just think
- back a few years when it actually meant what it says! (The
- cynical may choose instead to ponder the benefits of
- standardization.)
-
- When doing VDI output, it helps if you pretend that the
- display screen really is a plotter or some other separate device,
- which has its own internal parameters which you can set up and
- read back. The class of VDI commands called Attribute Functions
- let you set the parameters. Output Functions cause the "device"
- to actually draw someone once it is configured. The Inquire
- Functions let you read back the parameters if necessary.
-
- There are two parameters which are relevant no matter what
- type of object you are trying to draw. They are the writing mode
- and the clipping rectangle. The writing mode is similar to that
- discussed in the column on raster operations. It determines what
- effect the figure you are drawing will have on data already on the
- screen. The writing mode is set with the call:
-
- vswr_mode(vdi_handle, mode);
-
- (Vdi_handle, here and below, is the handle obtained from
- graf_handle at the beginning of the program. Mode is a word which
- may be one of:
-
- 1 - Replace Mode
- 2 - Transparent Mode
- 3 - XOR mode
- 4 - Reverse Transparent Mode
-
- In replace mode, whatever is on the screen is overwritten.
- If you are writing characters, this means the background of each
- character cell will be erased.
-
- In transparent mode, only the pixels directly under the
- "positive" part of the image, that is, where 1-bits are being
- written, will be changed. When writing characters, the background
- of the cell will be left intact.
-
- In XOR mode, an exclusive or is performed between the screen
- contents and what is being written. The effect is to reverse the
- image under areas where a 1-bit occurs.
-
- Reverse transparent is like transparent, but with a "reverse
- color scheme". That is, only places where a 0-bit is to be
- put are changed to the current writing color. When you
- write characters in reverse transparent (over white), the effect
- is reverse video.
-
- The other common parameter is the clipping rectangle. It
- defines the area on the screen where the VDI is permitted to draw.
- Any output which would fall outside of this area is ignored; it is
- effectively a null operation. The clip rectangle is set with the
- call:
-
- vs_clip(vdi_handle, flag, pxy);
-
- Pxy is a four-word array. Pxy[0] and pxy[1] are the X and Y
- screen coordinates, respectively, of one corner of your clipping
- rectangle. Pxy[2] and pxy[3] are the coordinates of the
- diagonally opposite corner of the rectangle. (When working with
- the AES, use of a GRECT to define the clip is often more
- convenient. The routine set_clip() in the download does this.)
-
- Flag is set to TRUE if clipping is to be used. If you set it
- to FALSE, the entire screen is assumed to be fair game.
-
- Normally, you should walk the rectangle list for the current
- window to obtain your clipping rectangles. (See ST PRO GEM #2 for
- more details.) However, turning off the clip speeds up all output
- operations, particularly text. You may do this ONLY when you are
- absolutely certain that the figure you are drawing will not extend
- out of the top-most window, or out of a dialog.
-
- THE LINE FORMS ON THE LEFT
-
- The VDI line drawing operations include polyline, arc,
- elliptical arc, and rounded rectangle. I'll first look at the
- Attribute Functions for line drawing, then go through the drawing
- primitives themselves.
-
- The most common used line attributes are color and width.
- The color is set with:
-
- vsl_color(vdi_handle, color);
-
- where color is one of the standard VDI color indices, ranging
- from zero to 15. (As discussed in column #6, the color which
- actually appears will depend on the pallette setting of your ST.)
-
- The line width may only be set to ODD positive values, for
- reasons of symmetry. If you try to set an even value, the VDI
- will take the next lower odd value. The call is:
-
- vsl_width(vdi_handle, width);
-
- The two less used line parameters are the end style and
- pattern. With the end style you can cause the output line to
- have rounded ends or arrowhead ends. The call is:
-
- vsl_ends(vdi_handle, begin_style, end_style);
-
- Begin_style and end_style are each words which may have the
- values zero for square ends (the default), one for arrowed ends,
- or two for rounded ends. They determine the styles for the
- starting and finishing ends of the line, respectively.
-
- The line pattern attribute can select dotted or dashed lines
- as well as more complicated patterns. Before continuing, you
- should note one warning: VDI line output DOES NOT compensate for
- pixel aspect ratio. That is, the dashes on a line will look twice
- as long drawn vertically on a medium-res ST screen as they do when
- drawn horizontally. The command for setting the pattern is:
-
- vsl_type(vdi_handle, style);
-
- Style is a word with a value between 1 and 7. The styles
- selected are:
-
- 1 - Solid (the default)
- 2 - Long Dash
- 3 - Dot
- 4 - Dash, Dot
- 5 - Dash
- 6 - Dash, Dot, Dot
- 7 - (User defined style)
-
- The user defined style is determined by a 16-bit pattern
- supplied by the application. A one bit in the pattern turns a
- pixel on, a zero bit leaves it off. The pattern is cycled through
- repeatedly, using the high bit first. To use a custom style, you
- must make the call:
-
- vsl_udsty(vdi_handle, pattern);
-
- before doing vsl_type().
-
- As I mentioned above, the line type Output Functions
- available are polyline, circular and ellliptical arc, and rounded
- rectangle. Each has its own calling sequence. The call for a
- polyline is:
-
- v_pline(vdi_handle, points, pxy);
-
- Points tells how many vertices will appear on the polyline. For
- instance, a straight line has two vertices: the end and the
- beginning. A closed square would have five, with the first and
- last identical. (There is no requirement that the figure
- described be closed.)
-
- The pxy array contains the X and Y raster coordinates for the
- vertices, with a total of 2 * points entries. Pxy[0] and pxy[1]
- are the first X-Y pair, and so on.
-
- If you happen to be using the XOR drawing mode, remember that
- drawing twice at a point is equivalent to no drawing at all.
- Therefore, for a figure to appear closed in XOR mode, the final
- stroke should actually stop one pixel short of the origin of the
- figure.
-
- You may notice that in the GEM VDI manual the rounded
- rectangle and arc commands are referred to as GDPs (Generalized
- Drawing Primitives). This denotation is historical in nature, and
- has no effect unless you are writing your own VDI bindings.
-
- The rounded rectangle is nice to use for customized buttons
- in windows and dialogs. It gives a "softer" look to the screen
- than the standard square objects. The drawing command is:
-
- v_rbox(vdi_handle, pxy);
-
- Pxy is a four word array giving opposite corners of the
- rectangle, just as for the vs_clip() call. The corner rounding
- occurs within the confines of this rectangle. Nothing will
- protrude unless you specify a line thickness greater than one.
- The corner rounding is approximately circular; there is no user
- control over the degree or shape of rounding.
-
- Both the arc and elliptical arc commands use a curious method
- of specifying angles. The units are tenths of degrees, so an
- entire circle is 3600 units. The count starts at ninety degrees
- right of vertical, and proceeds counterclockwise. This means that
- "3 o'clock" is 0 units, "noon" is 900 units, "9 o'clock" is 1800
- units, and 2700 units is at "half-past". 3600 units take you back
- to "3 o'clock".
-
- The command for drawing a circular arc is:
-
- v_arc(vdi_handle, x, y, radius, begin, end);
-
- X and y specify the raster coordinates of the center of the
- circle. Radius specifies the distance from center to all points
- on the arc. Begin and end are angles given in units as described
- above, both with values between 0 and 3600. The drawing of the
- arc ALWAYS proceeds counterclockwise, in the direction of
- increasing arc number. So values of 0 and 900 for begin and end
- would draw a quarter circle from "three o'clock" to "noon".
- Reversing the values would draw the other three quarters of the
- circle.
-
- A v_arc() command which specifies a "full turn" is the
- fastest way to draw a complete circle on the screen. Be warned,
- however, that the circle drawing algorithm used in the VDI seems
- to have some serious shortcomings at small radii! You can
- experiment with the CIRCLE primitive in ST Logo, which uses
- v_arc(), to see what I mean.
-
- Notice that if you want an arc to strike one or more given
- points on the screen, then you are in for some trigonometry. If
- your math is a bit rusty, I highly recommend the book "A
- Programmer's Geometry", by Bowyer and Woodwark, published by
- Butterworths (London, Boston, Toronto).
-
- Finally, the elliptical arc is generated with:
-
- v_ellarc(vdi_handle, x, y, xrad, yrad, begin, end);
-
- X, y, begin, and end are just as before. Xrad and yrad give the
- horizontal and vertical radii of the defining ellipse. This means
- that the distance of the arc from center will be yrad pixels at
- "noon" and "half-past", and it will be xrad pixels at "3 and 9
- o'clock". Again, the arc is always drawn counterclockwise.
-
- There are a number of approaches to keeping the VDI's
- attributes "in sync" with the actual output operations. Probably
- the LEAST efficient is to use the Inquire Functions to determine
- the current attributes. For this reason, I have omitted a
- discussion of these calls from this column.
-
- Another idea is to keep a local copy of all significant
- attributes, use a test-before-set method to minimize the number of
- Attribute Functions which need to be called. This puts a burden
- on the programmer to be sure that the local attribute variables
- are correctly maintained. Failure to do so may result in obscure
- drawing bugs. If your application employs user defined AES
- objects, you must be very careful because GEM might call your draw
- code in the middle of a VDI operation (particularly if the user
- defined objects are in the menu).
-
- Always setting the attributes is a simplistic method, but
- often proves most effective. The routines pl_perim() and
- rr_perim() in the download exhibit this approach. Modification
- for other primitives is straightforward. This style is most
- useful when drawing operations are scattered throughout the
- program, so that keeping track of the current attribute status is
- difficult. Although inherently inefficient, the difference is not
- very noticable if the drawing operation requested is itself time
- consuming.
-
- In many applications, such as data graphing programs or
- "Draw" packages, the output operations are centralized, forming
- the primary functionality of the code. In this case, it is both
- easy and efficient to keep track of attribute status between
- successive drawing operations.
-
- SOLIDS
-
- There are a wider variety of VDI calls for drawing solid
- figures. They include rectangle or bar, disk, pie, ellipse,
- elliptical pie, filled rounded rectangle, and filled polygonal
- area. Of course, filled figure calls also have their own set of
- attributes which you will need to set.
-
- The fill color index determines what pen color will be used
- to draw the solid. It is set with:
-
- vsf_color(vdi_handle, color);
-
- Color is just the same as for line drawing. A solid may or
- may not have a visible border. This is determined with the call:
-
- vsf_perimeter(vdi_handle, vis);
-
- Vis is a Boolean. If it is true, the figure will be given a
- solid one pixel outline in the current fill color index. This is
- often useful to improve the appearance of solids drawn with a
- dithered fill pattern. If vis is false, then no outline is drawn.
-
- There are two parameters which together determine the pattern
- used to fill your figure. They are called interior style and
- interior index. The style determines the general type of fill,
- and the index is used to select a particular pattern if necessary.
- The style is set with the command:
-
- vsf_interior(vdi_handle, style);
-
- where style is a value from zero through four. Zero selects a
- hollow style: the fill is performed in color zero, which is
- usually white. Style one selects a solid fill with the current
- fill color. A style of two is called "pattern" and a three is
- called "hatch", which are terms somewhat suggestive of the options
- which can then be selected using the interior index. Style four
- selects the user defined pattern, which is described below.
-
- The interior index is only significant for styles two and
- three. To set it, use:
-
- vsf_style(vdi_handle, index);
-
- (Be careful here: it is very easy to confuse this call with the
- one above due to the unfortunate choice of name.) The index
- selects the actual drawing pattern. The GEM VDI manual shows fill
- patterns corresponding to index values from 1 to 24 under style 2,
- and from 1 to 12 under style 3. However, some of these are
- implemented differently on the ST. Rather than try to describe
- them all here, I would suggest that you experiment. You can do so
- easily in ST Logo by opening the Graphics Settings dialog and
- playing with the style and index values there.
-
- The user defined style gives you some interesting options for
- multi-color fills. It is set with:
-
- vsf_udpat(vdi_handle, pattern, planes);
-
- Planes determines the number of color planes in the pattern
- which you supply. It is set to one if you are setting a
- monochrome pattern. (Remember, monochrome is not necessarily
- black). It may be set to higher values on color systems: two for
- ST medium-res mode, or four for low-res mode. If you use a number
- lower than four under low-res, the other planes are zero filled.
-
- The pattern parameter is an array of words which is a
- multiple of 16 words long. The pattern determined is 16 by 16
- pixels, with each word forming one row of the pattern. The rows
- are arranged top to bottom, with the most significant bit to the
- left. If you have selected a multi-plane pattern, the entire
- first plane is stored, then the second, and so on.
-
- Note that to use a multi-plane pattern, you set the writing
- mode to replace using vswr_mode(). Since the each plane can be
- different, you can produce multi-colored patterns. If you use a
- writing color other than black, some of the planes may
- "disappear".
-
- Most of the solids Output Functions have analogous line
- drawing commands. The polyline command corresponds to the filled
- area primitive. The filled area routine is:
-
- v_fillarea(vdi_handle, count, pxy);
-
- Count and pxy are just the same as for v_pline(). If the
- polygon defined by pxy is not closed, then the VDI will force
- closure with a straight line from the last to the first point.
- The polygon may be concave or self-intersecting. If perimeter
- show is on, the area will be outlined.
-
- One note of caution is necessary for both v_fillarea() and
- v_pline(). There is a limit on the number of points which may be
- stored in pxy[]. This limit occurs because the contents of pxy[]
- are copied to the intin[] binding array before the VDI is called.
- You can determine the maximum number of vertices by checking
- intout[14] after using the extended inquire function vq_extnd().
-
- For reasons unknown to this writer, there are TWO different
- filled rectangle commands in the VDI. The first is
-
- vr_recfl(vdi_handle, pxy);
-
- Pxy is a four word array defining two opposite corners of the
- rectangle, just as in vs_clip(). Vr_recfl() uses the fill
- attribute settings, except that it NEVER draws a perimeter.
-
- The other rectangle routine is v_bar(), with exactly the same
- arguments as vr_recfl(). The only difference is that the
- perimeter setting IS respected. These two routines are the
- fastest way to produce a solid rectangle using the VDI. They may
- be used in XOR mode with a BLACK fill color to quickly invert an
- area of the screen. You can improve the speed even further by
- turning off the clip (if possible), and byte aligning the left and
- right edges of the rectangle.
-
- Separate commands are provided for solid circle and ellipse.
- The circle call is:
-
- v_circle(vdi_handle, x, y, radius);
-
- and the ellipse command is:
-
- v_ellipse(vdi_handle, x, y, xrad, yrad);
-
- All of the parameters are identical to those given above for
- v_arc() and v_ellarc(). The solid analogue of an arc is a "pie
- slice". The VDI pie commands are:
-
- v_pieslice(vdi_handle, x, y, radius, begin, end);
-
- for a slice from a circular pie, and
-
- v_ellpie(vdi_handle, x, y, xrad, yrad, begin, end);
-
- for a slice from a "squashed" pie. Again, the parameters are
- identical to those in v_arc() and v_ellarc(). The units and
- drawing order of angles are also the same. The final solids
- Output Function is:
-
- v_rfbox(vdi_handle, pxy);
-
- which draws a filled rounded rectangle. The pxy array defines
- two two opposite corners of the bounding box, as shown for
- vs_clip().
-
- The issues involved in correctly setting the VDI attributes
- for a fill operation are identical to those in drawing lines. For
- those who want to employ the "always set" method, I have again
- included two skeleton routines in the download, which can be
- modified as desired.
-
- TO BE CONTINUED
-
- This concludes the first part of our expedition through basic
- VDI operations. The next issue will tackle the problems of
- drawing bit mapped text at a reasonable speed. This first pass
- will not attempt to tackle alternate or proportional fonts, or
- alternate font sizes. Instead, I will concentrate on techniques
- for squeezing greater performance out of the standard monospaced
- system fonts.
-