This is geomview, produced by Makeinfo version 3.12h from geomview.texi.

INFO-DIR-SECTION Graphics Applications
START-INFO-DIR-ENTRY
* Geomview: (geomview).         The interactive 3D viewing program.
END-INFO-DIR-ENTRY


File: geomview,  Node: OFF,  Next: VECT,  Prev: BBP and BEZ,  Up: Object File Formats

OFF Files
---------

   The conventional suffix for `OFF' files is `.off'.

   Syntax:

     [ST][C][N][4][n]OFF	# Header keyword
     [NDIM]		# Space dimension of vertices, present only if nOFF
     NVERTICES  NFACES  NEDGES   # NEdges not used or checked
     
     X[0]  Y[0]  Z[0]	# Vertices, possibly with normals,
     			# colors, and/or texture coordinates, in that order,
     			# if the prefixes `N', `C', `ST'
     			# are present.
     			# If 4OFF, each vertex has 4 components,
     			# including a final homogeneous component.
     			# If nOFF, each vertex has NDIM components.
     			# If 4nOFF, each vertex has NDIM+1 components.
     ...
     X[NVERTICES-1]  Y[NVERTICES-1]  Z[NVERTICES-1]
     
         			# Faces
         			# NV = # vertices on this face
         			# V[0] ... V[NV-1]: vertex indices
         			#		in range 0..NVERTICES-1
     NV  V[0] V[1] ... V[NV-1]  COLORSPEC
     ...
         			# COLORSPEC continues past V[NV-1]
         			# to end-of-line; may be 0 to 4 numbers
         			# nothing: default
         			# integer: colormap index
         			# 3 or 4 integers: RGB[A] values 0..255
     			# 3 or 4 floats: RGB[A] values 0..1

   `OFF' files (name for "object file format") represent collections of
planar polygons with possibly shared vertices, a convenient way to
describe polyhedra.  The polygons may be concave but there's no
provision for polygons containing holes.

   An `OFF' file may begin with the keyword `OFF'; it's recommended but
optional, as many existing files lack this keyword.

   Three ASCII integers follow: NVERTICES, NFACES, and NEDGES.  Thse
are the number of vertices, faces, and edges, respectively.  Current
software does not use nor check NEDGES; it needn't be correct but must
be present.

   The vertex coordinates follow: dimension * NVERTICES floating-point
values.  They're implicitly numbered 0 through NVERTICES-1.  dimension
is either 3 (default) or 4 (specified by the key character `4' directly
before `OFF' in the keyword).

   Following these are the face descriptions, typically written with
one line per face.  Each has the form
     N  VERT1 VERT2 ... VERTN  [COLOR]

Here N is the number of vertices on this face, and VERT1 through VERTN
are indices into the list of vertices (in the range 0..NVERTICES-1).

   The optional COLOR may take several forms.  Line breaks are
significant here: the COLOR description begins after VERTN and ends
with the end of the line (or the next # comment).  A COLOR may be:

nothing
     the default color

one integer
     index into "the" colormap; see below

three or four integers
     RGB and possibly alpha values in the range 0..255

three or four floating-point numbers
     RGB and possibly alpha values in the range 0..1

   For the one-integer case, the colormap is currently read from the
file `cmap.fmap' in Geomview's `data' directory.  Some better mechanism
for supplying a colormap is likely someday.

   The meaning of "default color" varies.  If no face of the object has
a color, all inherit the environment's default material color.  If some
but not all faces have colors, the default is gray (R,G,B,A=.666).

   A `[ST][C][N][n]OFF BINARY' format is accepted; *Note Binary
format::.  It resembles the ASCII format in almost the way you'd
expect, with 32-bit integers for all counters and vertex indices and
32-bit floats for vertex positions (and texture coordinates or vertex
colors or normals if `COFF'/`NOFF'/`CNOFF'/`STCNOFF'/etc. format).

   Exception: each face's vertex indices are followed by an integer
indicating how many color components accompany it.  Face color
components must be floats, not integer values.  Thus a colorless
triangular face might be represented as

     int int int int int
     3   17   5   9   0

   while the same face colored red might be

     int int int int int float float float float
      3  17   5   9   4   1.0   0.0   0.0   1.0


File: geomview,  Node: VECT,  Next: SKEL,  Prev: OFF,  Up: Object File Formats

VECT Files
----------

   The conventional suffix for `VECT' files is `.vect'.

   Syntax:

     [4]VECT
     NPOLYLINES  NVERTICES  NCOLORS
     
     NV[0] ... NV[NPOLYLINES-1]     # number of vertices
                                                # in each polyline
     
     NC[0] ... NC[NPOLYLINES-1]     # number of colors supplied
                                                # in each polyline
     
     VERT[0] ... VERT[NVERTICES-1]  # All the vertices
                                                # (3*NVertices floats)
     
     COLOR[0] ... COLOR[NCOLORS-1]  # All the colors
                                                # (4*NColors floats, RGBA)

   `VECT' objects represent lists of polylines (strings of connected
line segments, possibly closed).  A degenerate polyline can be used to
represent a point.

   A `VECT' file begins with the key word `VECT' or `4VECT' and three
integers: NLINES, NVERTICES, and NCOLORS.  Here NLINES is the number of
polylines in the file, NVERTICES the total number of vertices, and
NCOLORS the number of colors as explained below.

   Next come NLINES integers

                  NV[0] NV[1] NV[2] ... NV[NLINES-1]

   giving the number of vertices in each polyline.  A negative number
indicates a closed polyline; 1 denotes a single-pixel point.  The sum
(of absolute values) of the NV[I] must equal NVERTICES.

   Next come NLINES more integers Nc[i]: the number of colors in each
polyline.  Normally one of three values:

0
     No color is specified for this polyline.  It's drawn in the same
     color as the previous polyline.

1
     A single color is specified.  The entire polyline is drawn in that
     color.

abs(NV[I])
     Each vertex has a color.  Either each segment is drawn in the
     corresponding color, or the colors are smoothly interpolated along
     the line segments, depending on the implementation.

   The sum of the NC[I] must equal NCOLORS.

   Next come NVERTICES groups of 3 or 4 floating-point numbers: the
coordinates of all the vertices.  If the keyword is 4VECT then there
are 4 values per vertex.  The first abs(NV[0]) of them form the first
polyline, the next abs(NV[1]) form the second and so on.

   Finally NCOLORS groups of 4 floating-point numbers give red, green,
blue and alpha (opacity) values.  The first NC[0] of them apply to the
first polyline, and so on.

   A VECT BINARY format is accepted; *Note Binary format::.  The binary
format exactly follows the ASCII format, with 32-bit ints where
integers appear, and 32-bit floats where real values appear.


File: geomview,  Node: SKEL,  Next: SPHERE,  Prev: VECT,  Up: Object File Formats

SKEL Files
----------

   `SKEL' files represent collections of points and polylines, with
shared vertices.  The conventional suffix for `SKEL' files is `.skel'.

   Syntax:

     [4][n]SKEL
     [NDIM]                    # Vertex dimension, present only if nSKEL
     NVERTICES  NPOLYLINES
     
     X[0]  Y[0]  Z[0]      # Vertices
     				    # (if nSKEL, each vertex has NDim components)
     ...
     X[NVERTICES-1]  Y[NVERTICES-1]  Z[NVERTICES-1]
     
                             # Polylines
                             # NV = # vertices on this polyline (1 = point)
                             # V[0] ... V[NV-1]: vertex indices                        #               in range 0..NVERTICES-1
     NV  V[0] V[1] ... V[NV-1]  [COLORSPEC]
     ...
                             # COLORSPEC continues past V[NV-1]
                             # to end-of-line; may be nothing, or 3 or 4 numbers.
                             # nothing: default color
     			# 3 or 4 floats: RGB[A] values 0..1

   The syntax resembles that of `OFF' files, with a table of vertices
followed by a sequence of polyline descriptions, each referring to
vertices by index in the table.  Each polyline has an optional color.

   For `nSKEL' objects, each vertex has NDIM components.  For `4nSKEL'
objects, each vertex has NDIM+1 components; the final component is the
homogeneous divisor.

   No `BINARY' format is implemented as yet for `SKEL' objects.


File: geomview,  Node: SPHERE,  Next: INST,  Prev: SKEL,  Up: Object File Formats

SPHERE Files
------------

   The conventional suffix for `SPHERE' files is `.sph'.

     SPHERE
     RADIUS
     XCENTER YCENTER ZCENTER

   Sphere objects are drawn using rational Bezier patches, which are
diced into meshes; their smoothness, and the time taken to draw them,
depends on the setting of the dicing level, 10x10 by default.  From
Geomview, the Appearance panel, the `<N>ad' keyboard command, or a
`dice nu nv' Appearance attribute sets this.


File: geomview,  Node: INST,  Next: INST Examples,  Prev: SPHERE,  Up: Object File Formats

INST Files
----------

   The conventional suffix for a `INST' file is `.inst'.

   There is no INST BINARY format.

   An `INST' applies a 4x4 transformation to another OOGL object.  It
begins with `INST' followed by these sections which may appear in any
order:
     geom OOGL-OBJECT

specifies the OOGL object to be instantiated.  *Note References::, for
the syntax of an OOGL-OBJECT.  The keyword `unit' is a synonym for
`geom'.
     transform   ["{"] `4x4 transform' ["}"]

specifies a single transformation matrix.  Either the matrix may appear
literally as 16 numbers, or there may be a reference to a "transform"
object, i.e.
         "<" file-containing-4x4-matrix
   or
         ":" symbol-representing-transform-object>
   Another way to specify the transformation is
     transforms
         OOGL-OBJECT
   The OOGL-OBJECT must be a `TLIST' object (list of transformations)
object, or a `LIST' whose members are ultimately `TLIST' objects.  In
effect, the `transforms' keyword takes a collection of 4x4 matrices and
replicates the `geom' object, making one copy for each 4x4 matrix.

   If no `transform' nor `transforms' keyword appears, no
transformation is applied (actually the identity is applied).  You could
use this for, e.g., wrapping an appearance around an externally-supplied
object, though a single-membered LIST would do this more efficiently.

   *Note Transformation matrices::, for the matrix format.

   Two more INST fields are accepted: `location' and `origin'.

     location [global or camera or ndc or screen or local]
   Normally an INST specifies a position relative to its parent object;
the `location' field allows putting an object elsewhere.
   * `location global' attaches the object to the global (a.k.a.
     universe) coordinate system - the same as that in which geomview's
     World objects, alien geometry, and cameras are placed.

   * `location camera' places the object relative to the camera.  (Thus
     if there are multiple views, it may appear in a different spatial
     position in each view.)  The center of the camera's view is along
     its negative Z axis; positive X is rightward, positive Y upward.
     Normally the units of camera space are the same as global
     coordinates.  When a camera is reset, the global origin is at
     (0,0,-3.0).

   * `location ndc' places the object relative to the normalized unit
     cube into which the camera's projection (perspective or
     orthographic) maps the visible world.  X, Y, and Z are each in the
     range from -1 to +1, with Z = -1 the near and Z = +1 the far
     clipping plane, and X and Y increasing rightward and upward
     respectively.  Thus something like
          INST  transform  1 0 0 0  0 1 0 0  0 0 1 0  -.9 -.9 -.999 1
                location ndc
                geom < label.vect
     pastes `label.vect' onto the lower left corner of each window, and
     in front of nearly everything else, assuming `label.vect''s
     contents lie in the positive quadrant of the X-Y plane.  It's
     tempting to use -1 rather than -.999 as the Z component of the
     position, but that may put the object just nearer than the near
     clipping plane and make it (partially) invisible, due to
     floating-point error.

   * `location screen' places the object in screen coordinates.  The
     range of Z is still -1 through +1 as for ndc coordinates; X and Y
     are measured in pixels, and range from (0,0) at the _lower left_
     corner of the window, increasing rightward and upward.

   `location local' is the default; the object is positioned relative
to its parent.

     origin [global or camera or ndc or screen or local] x y z
   The `origin' field translates the contents of the INST to place the
origin at the specified point of the given coordinate system.  Unlike
`location', it doesn't change the orientation, only the choice of
origin.  Both `location' and `origin' can be used together.

   So for example
     { INST
       location screen
       origin ndc 0 0 -.99
       geom { < xyz.vect }
       transform { 100 0 0 0  0 100 0 0  0 0 -.009 0   0 0 0 1 }
     }

   places xyz.vect's origin in the center of the window, just beyond the
near clipping plane.  The unit-length X and Y edges are scaled to be
just 100 screen units - pixels - long, regardless of the size of the
window.

* Menu:

* INST Examples::	Some example of `INST' Files.


File: geomview,  Node: INST Examples,  Next: LIST,  Prev: INST,  Up: Object File Formats

INST Examples
.............

   Here are some examples of `INST' files

     INST
          unit < xyz.vect
          transform {
             1 0 0 0
             0 1 0 0
             0 0 1 0
             1 3 0 1
          }

     { appearance { +edge  material { edgecolor 1 1 0 } }
         INST geom < mysurface.quad }

     {INST transform {: T} geom {<dodec.off}}

     { INST
          transforms
              { LIST
          	{ < some-matrices.prj }
          	{ < others.prj }
          	{ TLIST <still more of them> }
     
              }
          geom
              { # stuff replicated by all the above matrices
          	...
              }
     }

   This one resembles the `origin' example in the section above, but
makes the X and Y edges be 1/4 the size of the window (1/4, not 1/2,
since the range of ndc X and Y coordinates is -1 to +1).
     { INST
       location ndc
       geom { < xyz.vect }
       transform { .5 0 0 0  0 .5 0 0  0 0 -.009 0   0 0 -.99 1 }
     }


File: geomview,  Node: LIST,  Next: TLIST,  Prev: INST Examples,  Up: Object File Formats

LIST Files
----------

   The conventional suffix for a `LIST' file is `.list'.

   A list of OOGL objects

   Syntax:

     LIST
         OOGL-OBJECT
         OOGL-OBJECT
         ...

   Note that there's no explicit separation between the oogl-objects, so
they should be enclosed in curly braces ({ }) for sanity.  Likewise
there's no explicit marker for the end of the list; unless appearing
alone in a disk file, the whole construct should also be wrapped in
braces, as in:

        { LIST { QUAD ... } { < xyz.quad } }

   A `LIST' with no elements, i.e. `{ LIST }', is valid, and is the
easiest way to create an empty object.  For example, to remove a
symbol's definition you might write

        { define somesymbol  { LIST } }


File: geomview,  Node: TLIST,  Next: GROUP,  Prev: LIST,  Up: Object File Formats

TLIST Files
-----------

   The conventional suffix for a `TLIST' file is `.grp' ("group") or or
`.prj' ("projective" matrices).

   Collection of 4x4 matrices, used in the `transforms' section of and
`INST' object.

   Syntax:

     TLIST			# key word
     
     <4x4 matrix (16 floats)>
     ...				# Any number of 4x4 matrices

   `TLIST's are used only within the `transforms' clause of an `INST'
object.  They cause the `INST's `geom' object to be instantiated once
under each of the transforms in the `TLIST'.  The effect is like that
of a `LIST' of `INST's each with a single transform, and all referring
to the same object, but is more efficient.

   Be aware that a `TLIST' is a kind of geometry object, distinct from a
`transform' object.  Some contexts expect one type of object, some the
other.  For example in
     INST transform { : MYT } geom { ... }

MYT must be a transform object, which might have been created with the
gcl
     (read transform { define myT 1 0 0 1 ... })

while in
         INST transforms { : MYTS } geom { ... }
     or  INST transforms { LIST {: MYTS} {< more.prj} } geom { ... }

MYTS must be a geometry object, defined e.g. with
         (read geometry { define MYTS { TLIST 1 0 0 1 ... } })

   A `TLIST BINARY' format is accepted.  Binary data begins with a
32-bit integer giving the number of transformations, followed by that
number of 4x4 matrices in 32-bit floating-point format.  The order of
matrix elements is the same as in the ASCII format.


File: geomview,  Node: GROUP,  Next: DISCGRP,  Prev: TLIST,  Up: Object File Formats

GROUP Files
-----------

   This format is obsolete, but is still accepted.  It combined the
functions of `INST' and `TLIST', taking a series of transformations and
a single Geom (`unit') object, and replicating the object under each
transformation.

     GROUP ... < matrices > ... unit { OOGL-OBJECT }

   is still accepted and effectively translated into

     INST
     	transforms { TLIST ... <matrices> ... }
     	unit { OOGL-OBJECT }


File: geomview,  Node: DISCGRP,  Next: COMMENT,  Prev: GROUP,  Up: Object File Formats

DISCGRP Files
-------------

   This format is for discrete groups, such as appear in the theory of
manifolds or in symmetry patterns.  This format has its own man page.
See discgrp(5).


File: geomview,  Node: COMMENT,  Next: Non-geometric objects,  Prev: DISCGRP,  Up: Object File Formats

COMMENT Objects
---------------

   The COMMENT object is a mechanism for encoding arbitrary data within
an OOGL object. It can be used to keep track of data or pass data back
and forth between external modules.

   Syntax:

     COMMENT                 # key word
     
     NAME TYPE   # individual name and type specifier
     { ... }             # arbitrary data

   The data, which must be enclosed by curly braces, can include
anything except unbalanced curly braces.  The TYPE field can be used to
identify data of interest to a particular program through naming
conventions.

   `COMMENT' objects are intended to be associated with other objects
through inclusion in a `LIST' object. (*Note LIST::.)  The "#" OOGL
comment syntax does not suffice for data exchange since these comments
are stripped when an OOGL object is read in to Geomview.  The `COMMENT'
object is preserved when loaded into Geomview and is written out intact.

   Here is an example associating a WorldWide Web URL with a piece of
geometry:

     { LIST
      { < Tetrahedron}
      {COMMENT GCHomepage HREF { http://www.geomview.org/ }}
     }

   A binary `COMMENT' format is accepted. Its format is not consistent
with the other OOGL binary formats. *Note Binary format::. The `name'
and `type' are followed by

     N BYTE1 BYTE2 ... BYTEN

   instead of data enclosed in curly braces.


File: geomview,  Node: Non-geometric objects,  Next: transform,  Prev: COMMENT,  Up: OOGL File Formats

Non-geometric objects
=====================

   The syntax of these objects is given in the form used in *Note
References::, where "quoted" items should appear literally but without
quotes, square bracketed ([ ]) items are optional, and | separates
alternative choices.

* Menu:

* transform::	Transformation matrices.
* camera::	Cameras.
* window::	Windows.


File: geomview,  Node: transform,  Next: camera,  Prev: Non-geometric objects,  Up: Non-geometric objects

Transform Objects
-----------------

   Where a single 4x4 matrix is expected - as in the `INST' `transform'
field, the camera's `camtoworld' transform and the Geomview `xform*'
commands - use a transform object.

   Note that a transform is distinct from a `TLIST', which is a type of
geometry.  `TLIST's can contain one or more 4x4 transformations;
"transform" objects must have exactly one.

   Why have both?  In many places - e.g. camera positioning - it's only
meaningful to have a single transform.  Using a separate object type
enforces this.

   Syntax for a transform object is

     <transform> ::=
       [ "{" ]             (curly brace, generally needed to make
                            the end of the object unambiguous.)
     
        [ "transform" ]    (optional keyword; unnecessary if the type
                            is determined by the context, which it
                            usually is.)
        [ "define" <name> ]
                           (defines a transform named <name>, setting
                            its value from the stuff which follows)
     
           <sixteen floating-point numbers>
                           (interpreted as a 4x4 homogeneous transform
     		       given row by row, intended to apply to a
                            row vector multiplied on its LEFT, so that e.g.
                            Euclidean translations appear in the bottom row)
        |
           "<" <filename>  (meaning: read transform from that file)
        |
           ":" <name>      (meaning: use variable <name>,
                             defined elsewhere; if undefined the initial
                             value is the identity transform)
     
      [ "}" ]              (matching curly brace)

   The whole should be enclosed in { braces }.  Braces are not essential
if exactly one of the above items is present, so e.g. a 4x4 array of
floats standing alone may but needn't have braces.

   Some examples, in contexts where they might be used:

     # Example 1: A gcl command to define a transform
     # called "fred"
     
     (read transform { transform  define fred
              1 0 0 0
              0 1 0 0
              0 0 1 0
             -3 0 1 1
         }
     )

     # Example 2:  A camera object using transform
     # "fred" for camera positioning
     # Given the definition above, this puts the camera at
     # (-3, 0, 1), looking toward -Z.
     
     { camera
             halfyfield 1
             aspect 1.33
             camtoworld { : fred }
     }


File: geomview,  Node: camera,  Next: window,  Prev: transform,  Up: Non-geometric objects

cameras
-------

   A camera object specifies the following properties of a camera:

position and orientation
     specified by either a camera-to-world or world-to-camera
     transformation; this transformation does not include the
     projection, so it's typically just a combination of translation
     and rotation.  Specified as a transform object, typically a 4x4
     matrix.

"focus" distance
     Intended to suggest a typical distance from the camera to the
     object of interest; used for default camera positioning (the
     camera is placed at (X,Y,Z) = (0,0,focus) when reset) and for
     adjusting field-of-view when switching between perspective and
     orthographic views.

window aspect ratio
     True aspect ratio in the sense <Xsize>/<Ysize>.  This normally
     should agree with the aspect ratio of the camera's window.
     Geomview normally adjusts the aspect ratio of its cameras to match
     their associated windows.

near and far clipping plane distances
     Note that both must be strictly greater than zero.  Very large
     <far>/<near> distance ratios cause Z-buffering to behave badly;
     part of an object may be visible even if somewhat more distant
     than another.

field of view
     Specified in either of two forms.
    `fov'
          is the field of view - in degrees if perspective, or linear
          distance if orthographic - in the _shorter_ direction.

    `halfyfield'
          is half the projected Y-axis field, in world coordinates (not
          angle!), at unit distance from the camera.  For a perspective
          camera, halfyfield is related to angular field:

                  halfyfield = tan( Y_axis_angular_field / 2 )

          while for an orthographic one it's simply:

                      halfyfield = Y_axis_linear_field / 2

     This odd-seeming definition is (a) easy to calculate with and (b)
     well-defined in both orthographic and perspective views.

   The syntax for a camera is:

     <camera> ::=
     
        [ "camera" ]			(optional keyword)
         [ "{" ]			(opening brace, generally required)
     	[ "define" <name> ]
     
     	"<" <filename>
           |
     	":" <name>
           |
     				(or any number of the following,
     				 in any order...)
     
     	"perspective"  {"0" | "1"}		(default 1)
     					(otherwise orthographic)
     
     	"stereo"       {"0" | "1"}		(default 0)
     					(otherwise mono)
     
     	"worldtocam" <transform>	(see transform syntax above)
     
     	"camtoworld" <transform>
     				(no point in specifying both
     				 camtoworld and worldtocam; one is
     				 constrained to be the inverse of						 the other)
     
     	"halfyfield" <half-linear-Y-field-at-unit-distance>
     				(default tan 40/2 degrees)
     
     	"fov"		(angular field-of-view if perspective,
     			 linear field-of-view otherwise.
     			 Measured in whichever direction is smaller,
     			 given the aspect ratio.  When aspect ratio
     			 changes -- e.g. when a window is reshaped --
     			 "fov" is preserved.)
     
     	"frameaspect" <aspect-ratio>	(X/Y) (default 1.333)
     
     	"near"  <near-clipping-distance>	(default 0.1)
     
     	"far"	<far-clipping-distance>		(default 10.0)
     
     	"focus" <focus-distance>		(default 3.0)
     
     
          [ "}" ]				(matching closebrace)


File: geomview,  Node: window,  Next: Customization,  Prev: camera,  Up: Non-geometric objects

window
------

   A window object specifies size, position, and other window-system
related information about a window in a device-independent way.

   The syntax for a window object is:

     window ::=
     
     	[ "window" ]			(optional keyword)
     	  [ "{" ]			(curly brace, often required)
     
     	    			(any of the following, in any order)
     
     		"size"  <xsize> <ysize>
     				(size of the window)
     
     		"position"  <xmin> <xmax> <ymin> <ymax>
     				(position & size)
     
     
     		"noborder"
     				(specifies the window should
     				 have no window border)
     
     		"pixelaspect"  <aspect>
     			    (specifies the true visual aspect ratio
     			     of a pixel in this window in the sense
     			     xsize/ysize, normally 1.0.
     			     For stereo hardware which stretches the
     			     display vertically by a factor of 2,
     			     ``pixelaspect 0.5'' might do.
     			     The value is used when computing the
     			     projection of a camera associated with
     			     this window.)
     
     	  [ "}" ]			(matching closebrace)

   Window objects are used in the Geomview `window' and `ui-panel'
commands to set default properties for future windows or to change
those of an existing window.


File: geomview,  Node: Customization,  Next: Modules,  Prev: window,  Up: Top

Customization: `.geomview' files
********************************

   When Geomview is started, it loads and executes commands in a
system-wide startup file named `.geomview'.  This file is in the `data'
subdirectory of the Geomview distribution directory and contains gcl
commands to configure Geomview in a way common to all users on the
system.

   Next, Geomview looks for the file `~/.geomview' (`~' stands for your
home directory).  You can use this to configure your own default
Geomview behavior to suit your tastes.

   After reading `~/.geomview', Geomview looks for a file named
`.geomview' in the current directory.  If such a file exists Geomview
reads it, unless it is the same as `~/.geomview' (which would be the
case if you are running Geomview from your home directory).  You can
use the current directory's `.geomview' to create a Geomview
customization specific to a certain project.

   You can use `.geomview' files to control all kinds of things about
Geomview.  They can contain any valid gcl statements.  Especially
useful is the `ui-panel' command which controls the initial placement
of Geomview's panels.  For an example see the system-wide `.geomview'
file mentioned above.  For details of gcl, *Note GCL::.

   It is a good idea to enclose all the commands you put in a
`.geomview' file in a `progn' statement in order to cause Geomview to
execute them all at once.  Otherwise Geomview might execute them
sequentially over the first few refresh cycles after starting up.


File: geomview,  Node: Modules,  Next: Interface,  Prev: Customization,  Up: Top

External Modules
****************

   An external module is a program that interacts with Geomview.  A
module communicates with Geomview through gcl and can control any
apsect of Geomview that you can control through Geomview's user
interface.

   In many cases an external module is a specialized program that
implements some mathematical algorithm that creates a geometric object
that changes shape as the algorithm progresses.  The module informs
Geomview of the new object shape at each step, so the object appears to
evolve with time in the Geomview window.  In this way Geomview serves
as a _display engine_ for the module.

   An external module may be interactive.  It can respond to mouse and
keyboard events that take place in a Geomview window, thus extending
the capability of Geomview itself.

* Menu:

* Interface::               How External Modules Interface with Geomview.
* Example1::                Simple External Module.
* Example2::                Simple External Module with FORMS Control Panel.
* Forms::                   The FORMS Library.
* Example3::                External Module with Bi-Directional Communication.
* Example4::                Simple Tcl/Tk Module Demonstrating Picking.
* Module Installation::     Module Installation.


File: geomview,  Node: Interface,  Next: Example1,  Prev: Modules,  Up: Modules

How External Modules Interface with Geomview
============================================

   External modules appear in the _Modules_ browser in Geomview's
_Main_ panel.  To run a module, click the left mouse button on the
module's entry in the browser.  While the module is running, an
additional line for that module will appear in red in the browser.
This line begins with a number in brackets, which indicates the
_instace_ number of the module.  (For some modules it makes sense to
have more than one instance of the module running at the same time.)
You can kill an external module by clicking on its red instance entry.

   By default when Geomview starts, it displays all the modules that
have been installed on your system.

   For instructions on installing a module on your system so that it
will appear in the _Modules_ browser every time Geomview is run by
anyone on your system, *Note Module Installation::.

   When Geomview invokes an external module, it creates pipes connected
to the module's standard input and output. (Pipes are like files except
they are used for communication between programs rather than for
storing things on a disk.)  Geomview interprets anything that the
module writes to its standard output as a gcl command.  Likewise, if
the external module requests any data from Geomview, Geomview writes
that data to the module's standard input.  Thus all a module has to do
in order to communicate with Geomview is write commands to standard
output and (optionally) receive data on standard input.  Note that this
means that the module cannot use standard input and output for
communicating with the user.  If a module needs to communicate with the
user it can do so either through a control panel of its own or else by
responding to certain events that it finds out about from Geomview.


File: geomview,  Node: Example1,  Next: Example2,  Prev: Interface,  Up: Modules

Example 1: Simple External Module
=================================

   This section gives a very simple external module which displays an
oscillating mesh.  To try out this example, make a copy of the file
`example1.c' (it is distributed with Geomview in the `doc'
subdirectory) in your directory and compile it with the command

     cc -o example1 example1.c -lm

   Then put the line

     (emodule-define "Example 1" "./example1")

in a file called `.geomview' in your current directory.  Then invoke
Geomview; it is important that you compile the example program, create
the `.geomview' file, and invoke Geomview all in the same directory.
You should see "Example 1" in the _Modules_ browser of Geomview's
_Main_ panel; click on this entry in the browser to start the module.
A surface should appear in your camera window and should begin
oscillating.  You can stop the module by clicking on the red "[1]
Example 1" line in the _Modules_ browser.

     /*
      * example1.c: oscillating mesh
      *
      * This example module is distributed with the Geomview manual.
      * If you are not reading this in the manual, see the "External
      * Modules" chapter of the manual for more details.
      *
      * This module creates an oscillating mesh.
      */
     
     #include <math.h>
     #include <stdio.h>
     
     /* F is the function that we plot
      */
     float F(x,y,t)
          float x,y,t;
     {
       float r = sqrt(x*x+y*y);
       return(sin(r + t)*sqrt(r));
     }
     
     main(argc, argv)
          char **argv;
     {
       int xdim, ydim;
       float xmin, xmax, ymin, ymax, dx, dy, t, dt;
     
       xmin = ymin = -5;             /* Set x and y            */
       xmax = ymax = 5;              /*    plot ranges         */
       xdim = ydim = 24;             /* Set x and y resolution */
       dt = 0.1;                     /* Time increment is 0.1  */
     
       /* Geomview setup.  We begin by sending the command
        *            (geometry example { : foo})
        * to Geomview.  This tells Geomview to create a geom called
        * "example" which is an instance of the handle "foo".
        */
       printf("(geometry example { : foo })\n");
       fflush(stdout);
     
       /* Loop until killed.
        */
       for (t=0; ; t+=dt) {
         UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
       }
     }
     
     /* UpdateMesh sends one mesh iteration to Geomview.  This consists of
      * a command of the form
      *    (read geometry { define foo
      *       MESH
      *       ...
      *    })
      * where ... is the actual data of the mesh.  This command tells
      * Geomview to make the value of the handle "foo" be the specified
      * mesh.
      */
     UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
          float xmin, xmax, ymin, ymax, t;
          int xdim, ydim;
     {
       int i,j;
       float x,y, dx,dy;
     
       dx = (xmax-xmin)/(xdim-1);
       dy = (ymax-ymin)/(ydim-1);
     
       printf("(read geometry { define foo \n");
       printf("MESH\n");
       printf("%1d %1d\n", xdim, ydim);
       for (j=0, y = ymin; j<ydim; ++j, y += dy) {
         for (i=0, x = xmin; i<xdim; ++i, x += dx) {
           printf("%f %f %f\t", x, y, F(x,y,t));
         }
         printf("\n");
       }
       printf("})\n");
       fflush(stdout);
     }

   The module begins by defining a function `F(x,y,t)' that specifies a
time-varying surface.  The purpose of the module is to animate this
surface over time.

   The main program begins by defining some variables that specify the
parameters with which the function is to be plotted.

   The next bit of code in the main program prints the following line
to standard output

     (geometry example { : foo })

   This tells Geomview to create a geom called `example' which is an
instance of the handle `foo'.  _Handles_ are a part of the OOGL file
format which allow you to name a piece of geometry whose value can be
specified elsewhere (and in this case updated many times); for more
information on handles, *Note OOGL File Formats:: In this case,
`example' is the title by which the user will see the object in
Geomview's object browser, and `foo' is the internal name of the handle
that the object is a reference to.

   We then do `fflush(stdout)' to ensure that Geomview receives this
command immediately.  In general, since pipes may be buffered, an
external module should do this whenever it wants to be sure Geomview
has actually received everything it has printed out.

   The last thing in the main program is an infinite loop that cycles
through calls to the procedure `UpdateMesh' with increasing values of
`t'.  `UpdateMesh' sends Geomview a command of the form

     (read geometry { define foo
     MESH
     24 24
     ...
     })

where `...' is a long list of numbers.  This command tells Geomview to
make the value of the handle `foo' be the specified mesh.  As soon as
Geomview receives this command, the geom being displayed changes to
reflect the new geometry.

   The mesh is given in the format of an OOGL MESH.  This begins with
the keyword `MESH'.  Next come two numbers that give the x and y
dimensions of the mesh; in this case they are both 24.  This line is
followed by 24 lines, each containing 24 triples of numbers.  Each of
these triples is a point on the surface.  Then finally there is a line
with "`})'" on it that ends the "`{'" which began the `define'
statement and the "`('" that began the command.  For more details on
the format of MESH data, *note MESH::..

   This module could be written without the use of handles by having it
write out commands of the form

     (geometry example {
     MESH
     24 24
     ...
     })

This first time Geomview receives a command of this form it would create
a geom called `example' with the given `MESH' data.  Subsequent
`(geometry example ...)' commands would cause Geomview to replace the
geometry of the geom `example' with the new `MESH' data.  If done in
this way there would be no need to send the initial `(geometry example
{ : foo })' command as above.  The handle technique is useful, however,
because it can be used in more general situations where a handle
represents only part of a complex geom, allowing an external module to
replace only that part without having to retransmit the entire geom.
For more information on handles, *Note GCL::.

   The module loops through calls to `UpdateMesh' which print out
commands of the above form one after the other as fast as possible.
The loop continues indefinitely; the module will terminate when the
user kills it by clicking on its instance line in the _Modules_
browser, or else when Geomview exits.

   Sometimes when you terminate this module by clicking on its instance
entry the _Modules_ browser, Geomview will kill it while it is in the
middle of sending a command to Geomview.  Geomview will then receive
only a piece of a command and will print out a cryptic but harmless
error message about this.  When a module has a user interface panel it
can use a "Quit" button to provide a more graceful way for the user to
terminate the module.  See the next example.

   You can run this module in a shell window without Geomview to see the
commands it prints out.  You will have to kill it with `ctrl-C' to get
it to stop.


File: geomview,  Node: Example2,  Next: Forms,  Prev: Example1,  Up: Modules

Example 2: Simple External Module with FORMS Control Panel
==========================================================

   This section gives a new version of the above module -- one that
includes a user interface panel for controlling the velocity of the
oscillation.  We use the FORMS library by Mark Overmars for the control
panel.  The FORMS library is a public domain user interface toolkit for
IRISes; for more information *Note Forms::.

   To try out this example, make a copy of the file `example2.c'
(distributed with Geomview in the `doc' subdirectory) in your directory
and compile it with the command

     cc -I/u/gcg/ngrap/include -o example2 example2.c \
       -L/u/gcg/ngrap/lib/sgi -lforms -lfm_s -lgl_s -lm

   You should replace the string `/u/gcg/ngrap' above with the pathname
of the Geomview distribution directory on your system.  (The forms
library is distributed with Geomview and the `-I' and `-L' options above
tell the compiler where to find it.)

   Then put the line

     (emodule-define "Example 2" "./example2")

in a file called `.geomview' in the current directory and invoke
Geomview from that directory.  Click on the "Example 2" entry in the
_Modules_ browser to invoke the module.  A small control panel should
appear.  You can then control the velocity of the mesh oscillation by
moving the slider.

     /*
      * example2.c: oscillating mesh with FORMS control panel
      *
      * This example module is distributed with the Geomview manual.
      * If you are not reading this in the manual, see the "External
      * Modules" chapter of the manual for an explanation.
      *
      * This module creates an oscillating mesh and has a FORMS control
      * panel that lets you change the speed of the oscillation with a
      * slider.
      */
     
     #include <math.h>
     #include <stdio.h>
     #include <sys/time.h>           /* for struct timeval below */
     
     #include "forms.h"              /* for FORMS library */
     
     FL_FORM *OurForm;
     FL_OBJECT *VelocitySlider;
     float dt;
     
     /* F is the function that we plot
      */
     float F(x,y,t)
          float x,y,t;
     {
       float r = sqrt(x*x+y*y);
       return(sin(r + t)*sqrt(r));
     }
     
     /* SetVelocity is the slider callback procedure; FORMS calls this
      * when the user moves the slider bar.
      */
     void SetVelocity(FL_OBJECT *obj, long val)
     {
       dt = fl_get_slider_value(VelocitySlider);
     }
     
     /* Quit is the "Quit" button callback procedure; FORMS calls this
      * when the user clicks the "Quit" button.
      */
     void Quit(FL_OBJECT *obj, long val)
     {
       exit(0);
     }
     
     /* create_form_OurForm() creates the FORMS panel by calling a bunch of
      * procedures in the FORMS library.  This code was generated
      * automatically by the FORMS designer program; normally this code
      * would be in a separate file which you would not edit by hand.  For
      * simplicity of this example, however, we include this code here.
      */
     create_form_OurForm()
     {
       FL_OBJECT *obj;
       FL_FORM *form;
       OurForm = form = fl_bgn_form(FL_NO_BOX,380.0,120.0);
       obj = fl_add_box(FL_UP_BOX,0.0,0.0,380.0,120.0,"");
       VelocitySlider = obj = fl_add_valslider(FL_HOR_SLIDER,20.0,30.0,
                                               340.0,40.0,"Velocity");
         fl_set_object_lsize(obj,FL_LARGE_FONT);
         fl_set_object_align(obj,FL_ALIGN_TOP);
         fl_set_call_back(obj,SetVelocity,0);
       obj = fl_add_button(FL_NORMAL_BUTTON,290.0,75.0,70.0,35.0,"Quit");
         fl_set_object_lsize(obj,FL_LARGE_FONT);
         fl_set_call_back(obj,Quit,0);
       fl_end_form();
     }
     
     main(argc, argv)
          char **argv;
     {
       int xdim, ydim;
       float xmin, xmax, ymin, ymax, dx, dy, t;
       int fdmask;
       static struct timeval timeout = {0, 200000};
     
       xmin = ymin = -5;             /* Set x and y            */
       xmax = ymax = 5;              /*    plot ranges         */
       xdim = ydim = 24;             /* Set x and y resolution */
       dt = 0.1;                     /* Time increment is 0.1  */
     
       /* Forms panel setup.
        */
       foreground();
       create_form_OurForm();
       fl_set_slider_bounds(VelocitySlider, 0.0, 1.0);
       fl_set_slider_value(VelocitySlider, dt);
       fl_show_form(OurForm, FL_PLACE_SIZE, TRUE, "Example 2");
     
     
       /* Geomview setup.
        */
       printf("(geometry example { : foo })\n");
       fflush(stdout);
     
       /* Loop until killed.
        */
       for (t=0; ; t+=dt) {
         fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
         select(qgetfd()+1, &fdmask, NULL, NULL, &timeout);
         fl_check_forms();
         UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
       }
     }
     
     /* UpdateMesh sends one mesh iteration to Geomview
      */
     UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
          float xmin, xmax, ymin, ymax, t;
          int xdim, ydim;
     {
       int i,j;
       float x,y, dx,dy;
     
       dx = (xmax-xmin)/(xdim-1);
       dy = (ymax-ymin)/(ydim-1);
     
       printf("(read geometry { define foo \n");
       printf("MESH\n");
       printf("%1d %1d\n", xdim, ydim);
       for (j=0, y = ymin; j<ydim; ++j, y += dy) {
         for (i=0, x = xmin; i<xdim; ++i, x += dx) {
           printf("%f %f %f\t", x, y, F(x,y,t));
         }
         printf("\n");
       }
       printf("})\n");
       fflush(stdout);
     }

   The code begins by including some header files needed for the event
loop and the FORMS library.  It then declares global variables for
holding a pointer to the slider FORMS object and the velocity `dt'.
These are global because they are needed in the slider callback
procedure `SetVelocity', which forms calls every time the user moves the
slider bar. `SetVelocity' sets `dt' to be the new value of the slider.

   `Quit' is the callback procedure for the _Quit_ button; it provides
a graceful way for the user to terminate the program.

   The procedure `create_panel' calls a bunch of FORMS library
procedures to set up the control panel with slider and button.  For more
information on using FORMS to create interface panels see the FORMS
documentation.  In particular, FORMS comes with a graphical panel
designer that lets you design your panels interactively and generates
code like that in `create_panel'.

   This example's main program is similar to the previous example, but
includes extra code to deal with setting up and managing the FORMS
panel.

   To set up the panel we call the GL procedure `foreground' to cause
the process to run in the foreground.  By default GL programs run in the
background, and for various reasons external modules that use FORMS
(which is based on GL) need to run in the foreground.  We then call
`create_panel' to create the panel and `fl_set_slider_value' to set the
initial value of the slider.  The call to `fl_show_form' causes the
panel to appear on the screen.

   The first three lines of the main loop, starting with
     fdmask = (1 << fileno(stdin)) | (1 << qgetfd());

check for and deal with events in the panel.  The call to `select'
imposes a delay on each pass through the main loop.  This call returns
either after a delay of 1/5 second or when the next GL event occurs, or
when data appears on standard input, whichever comes first.  The
`timeout' variable specifies the amount of time to wait on this call;
the first member (0 in this example) gives the number of seconds, and
the second member (200000 in this example) gives the number of
microseconds.  Finally, `fl_check_forms()' checks for and processes any
FORMS events that have happened; in this case this means calling
`SetVelocity' if the user has moved the slider or calling `Quit' if the
user has clicked on the _Quit_ button.

   The purpose of the delay in the loop is to keep the program from
using excessive amounts of CPU time running around its main loop when
there are no events to be processed.  This is not so crucial in this
example, and in fact may actually slow down the animation somewhat, but
in general with external modules that have event loops it is important
to do something like this because otherwise the module will needlessly
take CPU cycles away from other running programs (such as Geomview!)
even when it isn't doing anything.

   The last line of the main loop in this example, the call to
`UpdateMesh', is the same as in the previous example.


File: geomview,  Node: Forms,  Next: Example3,  Prev: Example2,  Up: Modules

The FORMS Library
=================

   Geomview itself is written using Mark Overmar's public domain FORMS
library.  FORMS is a handy and relatively simple user interface toolkit
for IRISes.  Many Geomview external modules, including the examples in
this manual, use FORMS to create and manage control panels.

   We distribute a version of the FORMS library with Geomview because
it is necessary in order to compile Geomview and many of our modules.
If you use FORMS to write Geomview modules (or anything else, for that
matter) you may use this copy.  The header file `forms.h' is in the
`include' subdirectory, and the library file `libforms.a' is in the
`lib/sgi' subdirectory.  In particular, you can link the example
modules in this manual using this copy.

   FORMS is available via ftp on the Internet from a variety of sites,
including `cs.ruu.nl' or `glaurung.physics.mcgill.ca'.  It comes with
source code and extensive documentation.

   If you wish you may use any other interface toolkit instead of FORMS
in an external module.  We chose FORMS because it is free and relatively
simple.

