Professional GEM - Part IX - VDI Graphics: Lines and solids

From Atari Wiki
Revision as of 13:22, 13 September 2006 by Zorro 2 (talk | contribs)
Jump to navigation Jump to search


        Professional GEM                                               68


                                    PART IX

                        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.


        


        Professional GEM             Part IX                           69


        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: 

                           vswrmode(vdihandle, mode);

        Vdihandle,   here   and   below,   is the  handle  obtained  from
        grafhandle  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: 

                          vsclip(vdihandle, 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
        setclip() 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.  


        


        Professional GEM             Part IX                           70



             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: 

                           vslcolor(vdihandle, 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: 

                           vslwidth(vdihandle, 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: 

                    vslends(vdihandle, beginstyle, endstyle);

        Beginstyle   and  endstyle  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: 



        


        Professional GEM             Part IX                           71



                           vsltype(vdihandle, 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: 

                          vsludsty(vdihandle, pattern);

        before doing vsltype().  

             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: 

                         vpline(vdihandle, 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.  


        


        Professional GEM             Part IX                           72



             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: 

                             vrbox(vdihandle, pxy);

        Pxy   is   a  four word array  giving  opposite  corners  of  the
        rectangle,    just   as  for  the  vsclip()  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: 

                   varc(vdihandle, 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  varc()   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 varc(), 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).  



        


        Professional GEM             Part IX                           73



             Finally, the elliptical arc is generated with: 

                vellarc(vdihandle, 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
        plperim()    and   rrperim()    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


        


        Professional GEM             Part IX                           74


        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: 

                           vsfcolor(vdihandle, 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: 

                          vsfperimeter(vdihandle, 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: 

                         vsfinterior(vdihandle, 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: 

                           vsfstyle(vdihandle, 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.  


        


        Professional GEM             Part IX                           75



             The user  defined  style  gives you some interesting options
        for multi-color fills.  It is set with: 

                      vsfudpat(vdihandle, 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  vswrmode().   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: 

                        vfillarea(vdihandle, count, pxy);

        Count   and  pxy  are  just the same as  for  vpline().   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  vfillarea()
        and  vpline().    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 vqextnd().  

             For  reasons   unknown   to  this  writer,   there  are  TWO
        different filled rectangle commands in the VDI.  The first is 



        


        Professional GEM             Part IX                           76



                            vrrecfl(vdihandle, pxy);

        Pxy  is  a  four word array defining two opposite corners of  the
        rectangle,   just  as  in  vsclip().   Vrrecfl()  uses  the  fill
        attribute settings, except that it NEVER draws a perimeter.  

             The other  rectangle  routine  is  vbar(),  with exactly the
        same  arguments   as   vrrecfl().     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: 

                        vcircle(vdihandle, x, y, radius);

        and the ellipse command is: 

                     vellipse(vdihandle, x, y, xrad, yrad);

        All  of  the  parameters are identical to those given  above  for
        varc()   and vellarc().   The solid analogue of an arc is a  "pie
        slice".  The VDI pie commands are: 

                 vpieslice(vdihandle, x, y, radius, begin, end);

        for a slice from a circular pie, and 

                vellpie(vdihandle, x, y, xrad, yrad, begin, end);

        for  a  slice from a "squashed" pie.   Again,  the parameters are
        identical   to  those in varc() and  vellarc().   The  units  and
        drawing   order   of  angles  are  also  the   same.   The  final
        solids Output Function is: 

                             vrfbox(vdihandle, pxy);

        which  draws a filled rounded rectangle.   The pxy array  defines
        two   two   opposite   corners  of the  bounding  box,  as  shown
        for vsclip().  

             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.  


        


        Professional GEM             Part IX                           77




        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.  











































        

Back to Professional_GEM