YAODL Format (for SGI PowerFlip)

Yet Another Object Description Language

From SGI man page
Edited by Paul Bourke
November 1996

     YAODL - the 3D data format used by the powerflip demo

     YAODL stands for 'Yet Another Object Description Language', and is a
     format for three-dimensional models that supports NURBS, polygons, and
     quad-meshes, and object properties such as facet or vertex normals,
     texture coordinates, and object, facet and vertex colors.  It also
     supports hierarchical models, coordinate transformations (rotations,
     scales, translations), and instancing (using the same data more than
     once).  It is not an official data format of Silicon Graphics, it is just
     a data format created for the powerflip demo program.  This document is
     intended for intrepid programmers who want to display their data using
     the powerflip program, and for the terminally curious.

     A YAODL file consists of several YAODL objects separated by commas.  A
     YAODL object has one of the following forms:
     (object_type  argument1, argument2, ...)
     (object_type  argument1, ...  :  property1, property2, ... )
     integer integer integer ...
     float float float ...
     "Some Charater String"
     name = {one of the forms above}
     There is also a binary form that is described below.

     The set of object types and their expected arguments is described more
     fully below.  It will be simplest to start with a few examples of YAODL
     red = (colors 1.0 0.0 0.0),
     This defines a color called 'red'.  It might be used later like this:
     (polygons (vertices -1. -1. 0.     1. -1. 0.
        1.  1. 0.    -1.  1. 0.),
        : red),
     This defines one red square.  Red is a property of the polygon, so it
     must be specified after the ':' in the polygons object.  Properties
     affect only the object they are associated with (if there were other
     objects after the red square, the red color would not affect them).

     Why was the type of red 'colors' instead of 'color'?  In the YAODL file
     format, almost all types are plural; a 'colors' object can contain more
     than one color.  When matching up objects with their properties, they
     must have the same plurality.  So, for the red polygon example, there was
     one polygon (with 4 vertices) that matches up with one color.  If,
     instead, we wanted one polygon with a different color at each of its
     vertices we could have said:
     (polygons (vertices
       -1. -1. 0.      1. -1. 0.
        1.  1. 0.     -1.  1. 0.,
      : colors
          1. 0. 0.       0. 1. 0.
          0. 0. 1.       1. 1. 1.,
     Note that both the 'vertices' and the 'colors' types take one argument (a
     list of floating point values), and each 3 values define one vertex
     position or one RGB color.  Integers are not automatically converted to
     floating point values, so make sure your colors and vertices have decimal
     points in them.

     Each set of curly-braces defines a scope.  Names defined inside a scope
     are local to that scope and over-ride names in higher scopes. Names must
     be declared before they are referenced.

     A few more notes about syntax before describing the types more fully.
     There are two styles of comments allowed in a YAODL file; C-style
     (beginning with '/*' and ending with '*/' anywhere in the file) and
     Shell-style (beginning with '#' as the first character on the line and
     extending to the end of the line.  Comments are treated as whitespace,
     along with blanks, tabs, and new-lines, and are ignored by the parser,
     serving only to separate elements.

          Group is used to construct an object hierarchy.  Groups have an
          arbitrary number of arguments, each of which can be any YAODL
          object.  If there are properties associated with the group, then
          each property must have as many items as there are number of items
          in the group.  For example, if the YAODL object is (group  object1,
          object2 : colors) then there must be two colors in the colors array
          (the first will be the color of object1, then second the color of

          take a list of floats as an argument.  Every 3 floats defines one
          vertex.  Vertices don't mean anything by themselves; they are used
          as part of more complicated geometric type.  Normals, colors and
          texture coordinates are often used as properties of vertices.

          take a series of vertices as arguments.  Each vertices type defines
          one polygon.  Polygons are very inefficient; use of them is not
          recommended.  Wherever possible, use the more efficient
          indexpolygons (see below).  Normals and colors are often used as
          properties of polygons.  Example:
          /* Define two polygons, one red and one blue */
            (vertices  1.0 0.0 0.0  0.0 1.0 0.0  0.0 0.0 1.0),
            (vertices  1.0 0.0 0.0  0.0 1.0 0.0  3.2 0.0 1.0),
           : colors 1.0 0.0 0.0   0.0 1.0 0.0,

          takes an arbitrary number of arguments, each of which is a list of
          integers.  Indices are used in the indexpolygons type to re-use
          vertices in a list.

          takes two arguments; first a vertices object, and then an indices
          object.  The indices are used to form polygons out of the vertices
          in the vertex list.  The greatest integer in the indices list must
          be less than the number of vertices in the vertex list or an error
          will occur.  Normals and colors may be associated with the polygons
          (there must be as many normals or colors as there are arguments to
          the indices object).
            vertices  1.0 0.0 0.0   0.0 1.0 0.0  0.0 0.0 1.0  3.2 0.0 1.0,
            (indices  0 1 2,  0 1 3),   /* Two triangles */

          Defines a regular 3D mesh.  It expects two arguments.  The first
          argument is a list of 2 integers specifying how many rows and
          columns the mesh has.  The second is a vertices objects that must
          have rows*columns vertices in it.  The vertices are connected to
          form a grid in three-space.  The regularMesh primitive ignores any
          attributes associated with it, but you may associate colors and
          normals and texture coordinates with the vertices of the mesh, or
          encapsulate the mesh in a group and associate a color (or a texture
          or a contour) with the group.

          takes a list of floats.  Every 3 floats defines an RGB color.
          Colors should be associated with vertices, polygons, indexpolygons,
          or groups.  Example:
            vertices  1.0 0.0 0.0   0.0 1.0 0.0  0.0 0.0 1.0  3.2 0.0 1.0,
            (indices  0 1 2,  0 1 3),
            : colors 1.0 0.0 0.0  0.0 1.0 0.0 /* Red and blue flat-shaded tris

          take a list of floats.  Every 3 floats defines a normal vector.
          Normals should be associated with vertices or polygons.

          takes a list of floats.  Every 3 floats defines an XYZ translation.
          Translates are best associated with groups of objects.  Example:
          # Use the same object twice; once translated:
          wheel = ( ... some indexpolygons or something ...),
          wheel, (group  wheel : (translates 1.0 0.0 0.0)),

          takes a list of floats.  Every 3 floats defines how much to scale in
          the X, Y, and Z directions.  Scales are best associated with groups.

          takes a list of floats.  Every 4 floats defines an angle and an
          axis; the rotation will be a right-handed rotation of angle degrees
          about the given axis.  Rotates are best associated with groups.

          defines a NURBS surface.  It takes 4 arguments; a list of S knots, a
          list of T knots, 3 integers describing the number of control point
          in the S and T directions and the number of coordinates per control
          point (3 if it is a non-rational NURB, 4 if it is a rational NURB),
          and, finally, the control points themselves.  Normals and texture
          coordinates are automatically generated for the surface (YAODL does
          not allow you to change the default mapping).  The only object you
          may associate with a nurb is one or more trimcurves objects.  If you
          want to associate a texture or color with a nurb, encapsulate the
          nurb in a group and associate the texture or color with the group.

          defines a trimming curve for a NURBS surface.  It takes three
          arguments; a list of knots (floats), the number of control points
          and number of coordinates per control point (integers), and the
          control points (floats).  Trimcurves must be associated with a nurbs
          surface.  Example:
            -1. -1. -1. -1. 1. 1. 1. 1.,     /* S knots */
            1. -1. -1. -1. 1. 1. 1. 1., /* T knots */
            4 3,    /* Number of S control pts, number of T control pts,
                   * number of coordinates per control point
            -2.5 -3.7 1.0   -1.5  -3.7  3.0 /* Control points */
            1.5 -3.7 -2.5   2.5  -3.7  -.75
            -2.5 -2.0 3.0   -1.5  -2.0  4.0
            1.5 -2.0 -3.0   2.5  -2.0  0.0
            -2.5 2.0 1.0   -1.5 2.0  0.0
            1.5 2.0 -1.0   2.5  2.0  2.0
            -2.5 2.7 1.25   -1.5  2.7  .1
            1.5 2.7 -.6    2.5 2.7  .2,
            : (trimcurves
            0. 0. 0.  1. 1.  2. 2.  3. 3.   4. 4. 4.,  /* knots */
            9 3,    /* Number of control points, floats per pt */
            1.0 0.0 1.0   1.0 1.0 1.0   /* Control points
            0.0 2.0 2.0  -1.0 1.0 1.0
            -1.0 0.0 1.0 -1.0 -1.0 1.0
            0.0 -2.0 2.0  1.0 -1.0 1.0
            1.0 0.0 1.0),
            scales 0.2 0.2 0.2, textures "henry.rgb"),

          takes a series of character strings, each of which is the name of an
          image file (in libimage.a format; the same format used by snapshot,
          etc) to be used as a texture map.  Textures should be associated
          with groups of objects.

          takes floats as it argument.  Each 2 floats defines s and t
          coordinates; texcoords should be associated with vertices.

          Contours is a way of automatically generating texture coordinates
          from a geometry.  There are three modes available, corresponding to
          the three GL texgen(3G) function.  It expects 3 arguments; the first
          is a string, either "contour", "linear", "spheremap" or "off".  The
          second argument is also a character string; either "eye" or
          "object", specifying which space the texture coordinates should be
          specified in.  The third argument is a list of 4 floating point
          values, specifying the plane equation for "linear" and "contour"
          mode (the values are ignored for "off" and "spheremap" modes, but
          must still be present).  See the GL texgen() manual page for more

     A binary object can appear anywhere in a YAODL file; ASCII and binary may
     be freely intermixed (so, for example, you can 'cat' together an ASCII
     and binary yaodl file and get a valid YAODL file).  Binary objects have
     two main advantages over their ASCII form; they are much, much faster to
     read in and they generally take up about half the space.  The main
     disadvantage is that the binary format is unportable.  Since it isn't
     expected that YAODL will migrate to any other computer architectures,
     this shouldn't be a problem.

     A binary object starts with an '@' character.  Following the '@'
     character is a NULL-terminated string which identifies the type of the
     object (one of the types mentioned above), and a long (8-byte) integer
     which specifies how many bytes of raw binary data follows.  The format of
     the raw data depends on the type; the following types implement their own
     binary formats:

          This type is just the list of floating point values type.  The
          spaces before and after the class name identify it as a basic,
          built-in type.  The format of the data is just raw floating point
          values; number_of_bytes/sizeof(float) values will be read (where
          number_of_bytes is the long integer that follows the type name).

      int This is the built-in integer class.  The data is just raw integers;
          number_of_bytes/sizeof(int) integer values follow.

          The binary format for the indices type is layed out as follows:
          '@'  "indices" number_of_bytes  number_of_lists
          lengths[number_of_lists]  data
          The number_of_lists specifies how many arguments (groups of
          integers) this object has.  It is an integer.  Next, the length of
          each group of integers is given (these lengths are also integers).
          Finally, the data in all of the lists is given; the first lengths[0]
          items in the data array are the first argument, the next lengths[1]
          items are the second, etc.  These data values are also integers.

     There are probably a lot of bugs lurking in YAODL.  It is probably
     possible to work around most of them.

     There is also a lot of missing functionality in YAODL.  It is expected
     that future software products from Silicon Graphics will make YAODL
     obsolete and fill in the missing functionality.