💾 Archived View for gemini.quux.org › 9 › Archives › mirrors › x2ftp.oulu.fi › pub › msdos › program… captured on 2024-08-18 at 23:00:27.

View Raw

More Information

-=-=-=-=-=-=-











                           OFF - A 3D Object File Format


                                   Randi J. Rost
                                  6-November-1986
                              Updated 12-October-1989

                           Digital Equipment Corporation
                          Workstation Systems Engineering
                                 100 Hamilton Ave.
                                Palo Alto, Ca. 94301


                      This  document  describes  the  data   format
                 developed by WSE for the interchange and archiving
                 of three-dimensional objects.  This format, called
                 OFF  (for  Object File Format), is general, flexi-
                 ble, and extensible.  It supports ASCII text  ver-
                 sions  of  objects for the purpose of interchange,
                 and binary versions for efficiency of reading  and
                 writing.   It  is  assumed  that applications will
                 develop  their  own,  more  efficient  format  for
                 internal   storage   and   operation   on   three-
                 dimensional objects.




            _1.  _I_n_t_r_o_d_u_c_t_i_o_n

                 One of the most time-consuming tasks in computer anima-
            tion  projects is designing the 3D models that will be used.
            Many computer animation houses  have  found  that  owning  a
            large  number  of databases makes it easier for them to take
            on new projects at a lower cost (time and $$).  The cost of
            initially  creating  an  object  can  be  amortized over the
            number of times it can be re-used.  It is our  intention  to
            promote  the  use of OFF files within (and perhaps even out-
            side of) Digital in an effort to build up our collection  of
            useful 3D models.

                 The file format itself is not limiting:  OFF files  can
            be  used  for  a  wide variety of object types.  None of the
            "policy decisions" are hard-wired in the design of the  file
            format,  or in the support library routines that allow read-
            ing and writing of OFF files.  Rather, the policy  decisions
            have been left up to the designers since the format supports
            "generic" object definitions.  We  have  developed  specific
            conventions for objects that are defined by polygons for use




                                   April 26, 1990






                                       - 2 -


            within WSE, and we'd encourage others to adopt these conven-
            tions  as well in order to promote the interchange of useful
            object data bases.  The _d_x_m_o_d_e_l application (also  developed
            by WSE) is an example of an application that permits reading
            and writing of OFF files.

                 This paper describes the Object File Format itself, the
            conventions we've adopted at WSE, and the library of support
            routines that can be used to read and write OFF files.


            _2.  _D_e_s_i_g_n _G_o_a_l_s _a_n_d _N_o_n-_G_o_a_l_s

            Design goals for the Object File Format include:

            1)   Simple.  Simple cases should be simple.  It  should  be
                 possible  to type in all the data required for a simple
                 object (such as a cube) by hand.

            2)   Powerful.  The Object File Format should be capable  of
                 accomodating   complicated   objects   (many  vertices,
                 polygons, and a wide range of attributes).

            3)   Portable.  ASCII text file representation required  for
                 portability  across  operating  systems  and  hardware.
                 This also allows operations on OFF  files  by  familiar
                 system utilities (text editors and the like).

            4)   Efficient.  Binary text file representation required to
                 allow  efficient  reading and writing of OFF files.  It
                 is assumed that reading/writing an object is  a  costly
                 operation,  but  reading and writing ASCII data is just
                 _t_o_o slow.

            5)   General.  The format should address the general case of
                 the  three-dimensional  object, not a single particular
                 case.

            6)   Extensibile.   Make  sure  the  format  can  be  easily
                 extended to eventually support other primitives such as
                 bezier patches.

            7)   No  Favors.   Avoid   hard-wiring   policy   decisions.
                 Rather, provide generic building blocks capable of sup-
                 porting several styles and document a set  of  strongly
                 encouraged conventions that we have adopted.

            There are also things that were  specifically  non-goals  in
            the design of the Object File Format.

            1)   Internal  Format.   The  Object  File  Format  is   not
                 intended  to be forced upon applications as an internal




                                   April 26, 1990






                                       - 3 -


                 format that must be used.  Rather, it  should  be  con-
                 sidered  a  means  for  inputting and outputting object
                 descriptions in a  device-,  language-,  and  operating
                 system-independent  format.   Applications  should feel
                 free to develop and maintain the most  useful/efficient
                 data format they can, and only convert to/from OFF when
                 input or output of a standardized object is desired.

            2)   Object Conventions.   OFF  conventions  are  documented
                 only  for  objects in polygonal form at this point.  It
                 is anticipated that  the  Object  File  Format  can  be
                 easily  extended  to  handle bezier surface patches and
                 other primitives in the future.

            _3.  _O_b_j_e_c_t_s

                 For the purposes of the Object File Format, we'll adopt
            a very general definition of an _o_b_j_e_c_t.  An _o_b_j_e_c_t is simply
            a list of properties (name, description,  author,  copyright
            information, geometry data, colors, etc.)

                 The most important information about the object can  be
            found in the _h_e_a_d_e_r _f_i_l_e for the object.  The header file is
            always an ASCII text file  that,  by  convention,  is  named
            _n_a_m_e.aoff where _n_a_m_e is the object name.  See Appendix B for
            an example of an OFF object header file.

                 A few of these properties (name,  description,  author,
            copyright,  type)  are common to every type of 3D object and
            are considered standard properties.  The standard properties
            are built into the routines that manipulate 3D objects.  The
            rest of the properties may vary with the type of object, and
            so are defined by convention only.

                 The _n_a_m_e of an object is used to concisely describe the
            object  itself.   For  example, we have objects named "x29",
            "banana" and "vw".  By convention, this  name  also  becomes
            the  prefix for OFF data filenames when an object is read or
            written, so it is best to keep it fairly short.

                 The _d_e_s_c_r_i_p_t_i_o_n is used  to  more  fully  describe  the
            object itself.  It may contain the time and date of creation
            or more prose describing the object.

                 The _a_u_t_h_o_r should be the name of the  person  (or  com-
            pany, or utility) that created the object.  We should always
            try to give credit where credit is due.   This  field  tells
            you  who to thank for spiffy objects or whose cage to rattle
            when a problem with an OFF file is discovered.

                 The _c_o_p_y_r_i_g_h_t field contains information  dealing  with
            the  distribution of the object data.  Some object databases




                                   April 26, 1990






                                       - 4 -


            will be regarded by a company as proprietary.  These objects
            should  not be copied or distributed without consent.  Other
            objects (vw, x29) were developed by companies or individuals
            and  can  be  copied or used as long as the copyright notice
            appears and proper credit is  given.   Still  other  objects
            (cube,  sphere, etc.) have been placed in the public domain.
            We have tried to be as careful  as  possible  in  preserving
            copyright  and  author  information  for the objects we have
            collected, but sometimes the information was  lost  or  una-
            vailable.   Be  sure  and  honor  copyright notices.  If you
            don't, you (or your company) could end up in big trouble.

                 The _t_y_p_e field contains the type of  the  object.   For
            now,  only one type of object is supported: polygon objects.
            It is  anticipated  that  polyline  and  surface  patch-type
            objects will be supported in the future as well.

                 Also contained in the object header file are lines that
            describe the various properties of the object.  Each line in
            the object header file that describes an  attribute  of  the
            object other than a standard attribute must contain the pro-
            perty name, the property type, the data format and either  a
            file  name or a string containing default data, depending on
            the property type.  Each of these four  items  is  an  ASCII
            string, separated by white space.

                 The _p_r_o_p_e_r_t_y  _n_a_m_e  uniquely  describes  the  property.
            Property  names  for  which we have defined conventions (see
            Appendix A) include geometry, polygon_colors, vertex_colors,
            back_faces,  vertex_order,  polygon_normals, vertex_normals,
            diffuse_coef, specular_coef, and specular_power.

                 OFF currently supports four  _p_r_o_p_e_r_t_y  _t_y_p_e_s:  _d_e_f_a_u_l_t,
            _g_e_n_e_r_i_c,  _i_n_d_e_x_e_d, and _i_n_d_e_x_e_d__p_o_l_y.  If a property is indi-
            cated to be of type _d_e_f_a_u_l_t, the part of the line after  the
            data  format  is  assumed  to contain some default data that
            will be applied to the entire object.  For instance, it  may
            make  sense  to  give  the entire object a default color and
            default diffuse and specular coefficients.

                 If the property type is  either  generic,  indexed,  or
            indexed_poly  (described more fully below), the remainder of
            the line is taken to be a file name that can be  opened  and
            read to obtain the information for the property.

                 The data format indicates what type  of  data  will  be
            found  on  the remainder of the line if the property type is
            default, otherwise what kind of data will be  found  in  the
            specified  file.   The data format is a string of characters
            (no spaces) that indicate the order and type  of  the  data.
            Supported primitive data types are:





                                   April 26, 1990






                                       - 5 -


            f -  A number stored internally as a 32-bit  floating  point
                 number

            d -  A number stored internally as a 64-bit double-precision
                 floating point number

            i -  A number stored internally as a 32-bit integer value

            h -  A number stored internally as a 16-bit integer value

            b -  A number stored internally as an 8-bit integer value

            s -  A 32-bit pointer to a null-terminated string of charac-
                 ters

                 If, for instance, you were interested in  using  32-bit
            floating  values  for  r, g, and b default color values, you
            might have a line in the object header file that reads

                    polygon_colors   default   fff   1.0   0.8   0.0


                 It is important to understand that in  all  cases,  the
            "string"  (s)  data  primitive  will indicate a pointer to a
            string that is stored internally in the data  block  for  an
            object and not the string itself.

            _4.  _A_S_C_I_I _P_r_o_p_e_r_t_y _F_i_l_e_s

                 OFF supports ASCII text files as a way of providing for
            language-,   hardware-,   and  operating  system-independent
            object data files.  The three types of data files  currently
            supported by OFF are generic, indexed, and indexed_poly.

            _4._1.  _G_e_n_e_r_i_c _F_i_l_e_s

                 Generic files contain only a _c_o_u_n_t  value  followed  by
            _c_o_u_n_t  data  items of the type specified by the data format.
            Each data item can be comprised of some combination  of  the
            primitive  data  types described in Section 3.  Generic data
            files are useful for storing attributes which are unique  at
            every vertex or polygon (such as color or normals).

                 String data items in ASCII generic files may  not  con-
            tain  spaces  or  other white space.  8-bit integers must be
            listed in the range 0-255.

                 See Appendix D for an example of an ASCII generic  data
            file.







                                   April 26, 1990






                                       - 6 -


            _4._2.  _I_n_d_e_x_e_d _F_i_l_e_s

                 Indexed files make use of a list of indices in order to
            reduce  the amount of data required to store a property, and
            to provide a useful level  of  indirection.   For  instance,
            indexed  files  are  commonly  used  to maintain per-polygon
            color information.  If an object has just five  colors,  the
            indexed  data file would contain the list of the five colors
            followed by an index from  one  to  five  for  each  of  the
            polygons  in  the  object.   If an application maintains the
            indirection, it is possible for the user  to  easily  select
            five different colors to be used on the model.

                 An indexed file begins with two integers  separated  by
            white  space:  the  number  of  data items and the number of
            indices that will be provided.  Following these  two  values
            is  the  list  of  data items that is to be used.  Each data
            item in this list can be some combination of  the  primitive
            types described in Section 3.  Following the data items is a
            list of indices each of which is a pointer  to  one  of  the
            items  in the list of data items.  The list of data items is
            assumed to begin starting at one, not zero.


            _4._3.  _I_n_d_e_x_e_d__P_o_l_y _F_i_l_e_s

                 Indexed_poly files take  advantage  of  a  connectivity
            list  to  reduce the amount of information needed to store a
            list  of  polylines,  polygons,  or  normals.   The   unique
            geometry items (e.g., vertices) are listed in the first part
            of the file.  Following this list is  a  connectivity  list.
            Each  line  in  the connectivity list contains a _c_o_u_n_t value
            followed by _c_o_u_n_t indices (pointers) to information  in  the
            geometry  list.   (Items  in  the  geometry list are indexed
            starting from one, not zero.)

                 The first line of an indexed_poly  data  file  contains
            three  integers, separated by white space.  The first number
            on  this  line  indicates   the   number   of   data   items
            (vertices/normals)  that follow, the second number indicates
            the number of polylines/polygons that follow the data  list,
            and  the  third indicates the total number of edges that are
            contained in the polyline/polygon connectivity list.

                 String data items in ASCII indexed_poly files  may  not
            contain spaces or other white space.  8-bit integers must be
            listed in the range 0-255.

                 See Appendix C for an example of an ASCII  indexed_poly
            file.






                                   April 26, 1990






                                       - 7 -


            _5.  _B_i_n_a_r_y _O_F_F _F_i_l_e_s

                 The same three types of data files described above  are
            also  supported  in  binary  format.   There are a few minor
            differences.


            _5._1.  _G_e_n_e_r_i_c _F_i_l_e_s

                 Binary generic files begin with the first  32-bit  word
            equal  to  OFF_GENERIC_MAGIC  as defined in the include file
            _o_f_f._h.  The second word in the file is the _c_o_u_n_t (number  of
            data  items  in  the file).  Following the _c_o_u_n_t is the data
            itself.

                 The data format in the header file describes the primi-
            tives  that make up each data item in the list.  Within each
            data item, floats,  doubles,  32-bit  integers,  and  string
            pointers will all begin on a word boundary.  16-bit integers
            will all begin on a half-word boundary.  Thus, if your  data
            format  for  the  data items in a generic data file is "bbb"
            (three byte values), each data item will be stored as  three
            bytes  followed  by  a null byte so that each data item will
            begin on a word boundary.  Strings begin with a 32-bit _c_o_u_n_t
            followed  by  _c_o_u_n_t characters followed by a null character.
            The string is null-padded so it will end on a word boundary.

                 (It is assumed that for strings,  the  length  will  be
            read and then the necessary memory will be allocated and the
            string read in.   This  eliminates  a  problem  with  having
            variable-length  data in the data files.  Anyway, strings in
            files are  really  only  there  for  symmetry  with  default
            values,  where  strings  are really useful.  The performance
            implications for files containing strings will  probably  be
            enough to prevent people from using them.)



            _5._2.  _I_n_d_e_x_e_d _F_i_l_e_s

                 Binary indexed files begin with the first  32-bit  word
            equal  to  OFF_INDEXED_MAGIC  as defined in the include file
            _o_f_f._h.  The second word in the file is the _c_o_u_n_t (number  of
            data  items  in  the  file).   The third word in the file is
            _n_u_m__i_n_d_i_c_e_s (number of indices in the index list).

                 Following these two integers is the data for  the  data
            item  list.  Each item in the data item list will begin on a
            word boundary.  The data format in the header file describes
            the  primitives  that  make  up  each data item in the list.
            Within each data item, floats, doubles, 32-bit integers, and
            string  pointers  will all begin on a word boundary.  16-bit




                                   April 26, 1990






                                       - 8 -


            integers will all begin on a half-word boundary.   Thus,  if
            your  data format for the data items in an indexed data file
            is "bbb" (three byte values), each data item will be  stored
            as  three  bytes  followed  by a null byte so that each data
            item will begin on a word boundary.  Strings  begin  with  a
            32-bit _c_o_u_n_t followed by _c_o_u_n_t characters followed by a null
            character.  The string is null-padded so it will  end  on  a
            word boundary.

                 Following the data item list is a list of index values.
            This  list  will also begin on a word boundary, however, the
            index values within this list are short integers and will be
            packed two to each 32-bit word.


            _5._3.  _I_n_d_e_x_e_d__P_o_l_y _F_i_l_e_s

                 Binary indexed_poly files begin with the  first  32-bit
            word  equal  to  OFF_INDEXED_POLY_MAGIC  as  defined  in the
            include file off.h.  The second word is the number  of  data
            items  in  the  vertex  list  (_n_p_t_s),  the third word is the
            number of polylines/polygons in the list (_n_p_o_l_y_s),  and  the
            fourth  word is the number of edges contained in the connec-
            tivity list (_n_c_o_n_n_e_c_t_s).

                 Starting at the fifth word in the file  is  a  list  of
            _n_p_t_s  data items, followed by _n_p_o_l_y_s short integers contain-
            ing polyline/polygon vertex counts,  followed  by  _n_c_o_n_n_e_c_t_s
            short  integers  which  are  indices  into the array of data
            items.  (This arrangement is slightly  different  than  that
            used  for  indexed_poly files in ASCII format for efficiency
            reasons.)

                 The same restrictions that apply to the data types  for
            generic  binary  files apply to indexed_poly binary files as
            well.  In addition, the vertex count array which follows the
            geometry data in an indexed_poly file will always begin on a
            word boundary.  The connectivity array that follows the ver-
            tex  count  array will not necessarily start on a word boun-
            dary, but will always begin  _n_p_o_l_y_s  *  _s_i_z_e_o_f(_s_h_o_r_t)  bytes
            after the start of the vertex count array.


            _6.  _O_f_f._a _a_n_d _O_b_j_e_c_t_s._h

                 An include file and a library of routines has been pro-
            vided  for  UNIX/C programmers to more easily manipulate OFF
            files.  The basic concepts of "reading"  and  "writing"  OFF
            files  are  supported  in  this  library  of  routines.  The
            library is a software layer on top of the  operating  system
            file  I/O  interface,  with  special knowledge of OFF files.
            This subroutine library provides a mechanism  for  accessing




                                   April 26, 1990






                                       - 9 -


            the  syntactical  elements  of  an object file, but makes no
            attempt to understand the semantics.   Higher  level  inter-
            faces can be layered on top.

                 The subroutine library refers to an object as a pointer
            to  an _O_F_F_O_b_j_D_e_s_c.  This structure contains a pointer to the
            first property in the property list.  It is defined as  fol-
            lows:

                    typedef struct
                        {
                        OFFProperty *FirstProp;     /* Pointer to first property in list */
                        } OFFObjDesc;


                 The information that describes the object is  contained
            in  a  linked  list  of property structures.  The first such
            structure in the list is pointed at by an _O_F_F_O_b_j_D_e_s_c  struc-
            ture.  The property structures have the form:

                    typedef struct _OFFProp
                        {
                        char        PropName[40];
                        int         PropType;
                        char        PropFileName[256];
                        int         PropCount;
                        char        DataFormat[40];
                        char        *PropData;
                        struct _OFFProp *NextProp;
                        } OFFProperty;


                 _P_r_o_p_N_a_m_e contains a string defining one of the property
            types  for  which  a  convention  has  been  defined.   This
            includes the property names "name", "author", "description",
            "copyright",    "comment",   "geometry",   "polygon_colors",
            "polygon_normal", etc.  For  a  complete  list  of  property
            names,  see  Appendix  A.  (The special attribute type "com-
            ment" is supported so that blank lines and comment lines can
            be preserved if an object file is read and then written.)

                 The  _P_r_o_p_T_y_p_e  field  contains   a   value   equal   to
            _O_F_F__D_E_F_A_U_L_T__D_A_T_A,   _O_F_F__G_E_N_E_R_I_C__D_A_T_A,  _O_F_F__I_N_D_E_X_E_D__D_A_T_A,  or
            _O_F_F__I_N_D_E_X_E_D__P_O_L_Y__D_A_T_A which defines the basic type  for  the
            property.

                 The _P_r_o_p_F_i_l_e_N_a_m_e is required if _P_r_o_p_T_y_p_e  is  something
            other   than   _O_F_F__D_E_F_A_U_L_T__D_A_T_A.    It   contains  a  string
            representing the name of the file  to  be  read/written  for
            this  attribute.   This  file name should _n_o_t contain a path
            leading up to the file itself, only the  actual  file  name.
            The  object  search path mechanism (see Section 7) should be




                                   April 26, 1990






                                       - 10 -


            used instead.

                 The _P_r_o_p_C_o_u_n_t indicates the actual number of data items
            associated with this particular attribute.  After reading in
            an object, properties of type _O_F_F__D_E_F_A_U_L_T__D_A_T_A will  have  a
            _P_r_o_p_C_o_u_n_t  of  one, properties of type _O_F_F__G_E_N_E_R_I_C__D_A_T_A will
            have a _P_r_o_p_C_o_u_n_t equal to the number of generic  data  items
            in the list, properties of type _O_F_F__I_N_D_E_X_E_D__D_A_T_A will have a
            _P_r_o_p_C_o_u_n_t equal to the number of  items  in  the  data  item
            list, and properties of type _O_F_F__I_N_D_E_X_E_D__P_O_L_Y__D_A_T_A will have
            a _P_r_o_p_C_o_u_n_t equal  to  the  number  of  data  items  in  the
            geometry list.

                 The _D_a_t_a_F_o_r_m_a_t field contains a  string  of  characters
            corresponding  to  primitive data items.  The composite type
            of the data for this property can then be deduced by looking
            at this field and applying the rules for padding to word and
            half-word boundaries.

                 The _P_r_o_p_D_a_t_a field contains a pointer  to  a  block  of
            memory  containing  the actual data for this property.  This
            data will have the same data  alignment  restrictions  as  a
            binary  file has, with the exception of strings.  As strings
            are read in, memory is malloc'ed to hold them and a  pointer
            to the string is stored in the appropriate field in the data
            list.  This means that all primitive data types will have  a
            fixed  size  and lengths and alignments can be computed more
            easily.

                 The _N_e_x_t_P_r_o_p field contains a pointer to the next  pro-
            perty structure in the property list.

                 The routines contained in the  subroutine  library  are
            defined below.


            #include "off.h"

            int OFFReadObj(Obj, FileName)
                    OFFObjDesc *Obj;
                    char *FileName;

            int OFFWriteObj(Obj, FileName, Directory, FileType);
                    OFFObjDesc *Obj;
                    char *FileName;
                    char *Directory;
                    int FileType;

            void OFFPackObj(Obj)
                    OFFObjDesc *Obj;

            void OFFPackProperty(Property)




                                   April 26, 1990






                                       - 11 -


                    OFFProperty *Property;

            int OFFReadGeneric(Property, FileName)
                    OFFProperty *Property;
                    char *FileName;

            int OFFWriteGeneric(Property, FileName, FileType)
                    OFFProperty *Property;
                    char *FileName;
                    int FileType;

            int OFFReadIndexed(Property, FileName)
                    OFFProperty *Property;
                    char *FileName;

            int OFFWriteIndexed(Property, FileName, FileType)
                    OFFProperty *Property;
                    char *FileName;
                    int FileType;

            int OFFReadIndexedPoly(Property, FileName)
                    OFFProperty *Property;
                    char *FileName;

            int OFFWriteIndexedPoly(Property, FileName, FileType)
                    OFFProperty *Property;
                    char *FileName;
                    int FileType;

            OFFObjDesc *OFFCreateObj()

            int OFFDestroyObj(Obj)
                    OFFObjDesc *Obj;

            OFFProperty *OFFAddProperty(Obj)
                    OFFObjDesc *Obj;

            int OFFRemoveProperty(Obj, PropertyName)
                    OFFObjDesc *Obj;
                    char *PropertyName;

            int OFFFreeProperty(Property)
                    OFFProperty *Property;


                 _O_F_F_R_e_a_d_O_b_j will attempt to open the object header  file
            named  _F_i_l_e_N_a_m_e  and  read  the  object data it contains.  A
            pointer to the constructed object structure will be returned
            in  _O_b_j  when  the object has been read.  An attempt will be
            made to open the specified file first as  given,  then  con-
            catenated  in turn with each of the directories specified by
            the environment search path variable _O_B_J__P_A_T_H.  The property




                                   April 26, 1990






                                       - 12 -


            list  for  the  object  is  built as the file is read.  Upon
            return, the client need only traverse the property list  and
            select the data it needs.  This routine calls _O_F_F_R_e_a_d_G_e_n_e_r_i_c
            and _O_F_F_R_e_a_d_I_n_d_e_x_e_d_P_o_l_y in  order  to  read  associated  data
            files.   _O_F_F_R_e_a_d_O_b_j  will return 0 if the read operation was
            successful, -1 otherwise.

                 _O_F_F_W_r_i_t_e_O_b_j will attempt to write the object pointed at
            by  _O_b_j  using the filename specified by _F_i_l_e_N_a_m_e.  The file
            will be written in the directory indicated by _D_i_r_e_c_t_o_r_y.  If
            _F_i_l_e_T_y_p_e  is _O_F_F__A_S_C_I_I, the file will be written as an ASCII
            text OFF file.  If _F_i_l_e_T_y_p_e is _O_F_F__B_I_N_A_R_Y, the file will  be
            written  as  a  binary  OFF file.  The property list for the
            object is traversed and each property of the object is writ-
            ten  out  in  turn.   This routine calls _O_F_F_W_r_i_t_e_G_e_n_e_r_i_c and
            _O_F_F_W_r_i_t_e_I_n_d_e_x_e_d_P_o_l_y in order to write associated data files.
            _O_F_F_W_r_i_t_e_O_b_j  will  return  0 if the write operation was suc-
            cessful, -1 otherwise.

                 _O_F_F_P_a_c_k_O_b_j attempts to _p_a_c_k the object  pointed  at  by
            _O_b_j.  Packing only applies to geometry and normals stored in
            indexed_polygon format.  See _O_F_F_P_a_c_k_P_r_o_p_e_r_t_y below.

                 _O_F_F_P_a_c_k_P_r_o_p_e_r_t_y packs the property pointed at  by  _P_r_o_-
            _p_e_r_t_y.   Packing can only be applied to indexed_polygon pro-
            perties with format ``fff''.  (This is normally the case for
            geometry  and  normals properties.) Packing works by sharing
            common data (vertex or normal) values.   Since  each  vertex
            and vertex normal of an object is usually shared by three or
            more polygons, this can save  a  great  deal  of  space  and
            rendering  time.  If _P_r_o_p_e_r_t_y could not be packed, it is not
            modified; otherwise the property data is changed in-place.

                 _O_F_F_R_e_a_d_G_e_n_e_r_i_c will read the generic  data  file  named
            _F_i_l_e_N_a_m_e  (here  _F_i_l_e_N_a_m_e  contains the full path name) into
            the property structure pointed at by _P_r_o_p_e_r_t_y.  This routine
            will  allocate  the  space  it needs in order to read in the
            data.  A pointer to this allocated data space will be stored
            in the _P_r_o_p_D_a_t_a field of the specified _p_r_o_p_e_r_t_y as described
            earlier.  The entire object, including all allocated  memory
            resources can later be deallocated by calling _O_F_F_D_e_s_t_r_o_y_O_b_j.
            This routine will not typically be called directly by appli-
            cations.  _O_F_F_R_e_a_d_G_e_n_e_r_i_c will return 0 if the read operation
            was successful, -1 otherwise.

                 _O_F_F_W_r_i_t_e_G_e_n_e_r_i_c will write the generic data  associated
            with _P_r_o_p_e_r_t_y into the file _F_i_l_e_N_a_m_e (here _F_i_l_e_N_a_m_e contains
            the full path name of the file to be written).  If  _F_i_l_e_T_y_p_e
            is _O_F_F__A_S_C_I_I, the file will be written as an ASCII text gen-
            eric data file.  If _F_i_l_e_T_y_p_e is _O_F_F__B_I_N_A_R_Y, the file will be
            written  as  a  binary generic data file.  This routine will
            not  typically   be   called   directly   by   applications.




                                   April 26, 1990






                                       - 13 -


            _O_F_F_W_r_i_t_e_G_e_n_e_r_i_c  will  return  0  if the write operation was
            successful, -1 otherwise.

                 _O_F_F_R_e_a_d_I_n_d_e_x_e_d will read the indexed  data  file  named
            _F_i_l_e_N_a_m_e  (here  _F_i_l_e_N_a_m_e  contains the full path name) into
            the property structure pointed at by _P_r_o_p_e_r_t_y.  This routine
            will  allocate  the  space  it needs in order to read in the
            data.  A pointer to this allocated data space will be stored
            in the _P_r_o_p_D_a_t_a field of the specified _p_r_o_p_e_r_t_y as described
            earlier.  The entire object, including all allocated  memory
            resources can later be deallocated by calling _O_F_F_D_e_s_t_r_o_y_O_b_j.
            This routine will not typically be called directly by appli-
            cations.  _O_F_F_R_e_a_d_I_n_d_e_x_e_d will return 0 if the read operation
            was successful, -1 otherwise.

                 _O_F_F_W_r_i_t_e_I_n_d_e_x_e_d will write the indexed data  associated
            with _P_r_o_p_e_r_t_y into the file _F_i_l_e_N_a_m_e (here _F_i_l_e_N_a_m_e contains
            the full path name of the file to be written).  If  _F_i_l_e_T_y_p_e
            is  _O_F_F__A_S_C_I_I,  the  file  will  be written as an ASCII text
            indexed data file.  If _F_i_l_e_T_y_p_e is _O_F_F__B_I_N_A_R_Y, the file will
            be written as a binary indexed data file.  This routine will
            not typically be called directly by  applications.   _O_F_F_W_r_i_-
            _t_e_I_n_d_e_x_e_d  will return 0 if the write operation was success-
            ful, -1 otherwise.

                 _O_F_F_R_e_a_d_I_n_d_e_x_e_d_P_o_l_y will read the indexed_poly data file
            named  _F_i_l_e_N_a_m_e  (here _F_i_l_e_N_a_m_e contains the full path name)
            into the property structure pointed at  by  _P_r_o_p_e_r_t_y.   This
            routine will allocate the space it needs in order to read in
            the data.  A pointer to this allocated data  space  will  be
            stored  in  the  _P_r_o_p_D_a_t_a field of the specified _p_r_o_p_e_r_t_y as
            described earlier.  The entire object, including  all  allo-
            cated  memory  resources can later be deallocated by calling
            _O_F_F_D_e_s_t_r_o_y_O_b_j.  This routine will not  typically  be  called
            directly  by applications.  _O_F_F_R_e_a_d_I_n_d_e_x_e_d_P_o_l_y will return 0
            if the read operation was successful, -1 otherwise.

                 _O_F_F_W_r_i_t_e_I_n_d_e_x_e_d_P_o_l_y will write  the  indexed_poly  data
            associated  with  _P_r_o_p_e_r_t_y  into  the  file  _F_i_l_e_N_a_m_e  (here
            _F_i_l_e_N_a_m_e contains the full path name of the file to be writ-
            ten).  If _F_i_l_e_T_y_p_e is _O_F_F__A_S_C_I_I, the file will be written as
            an ASCII  text  indexed_poly  data  file.   If  _F_i_l_e_T_y_p_e  is
            _O_F_F__B_I_N_A_R_Y,   the   file   will   be  written  as  a  binary
            indexed_poly data file.  This routine will not typically  be
            called  directly  by applications.  _O_F_F_W_r_i_t_e_I_n_d_e_x_e_d_P_o_l_y will
            return 0 if the write operation was  successful,  -1  other-
            wise.

                 _O_F_F_C_r_e_a_t_e_O_b_j allocates and  initializes  an  _O_F_F_O_b_j_D_e_s_c
            structure  A  pointer  to  the  newly-created  structure  is
            returned.  The null pointer is returned if the operation was
            unsuccessful.




                                   April 26, 1990






                                       - 14 -


                 _O_F_F_D_e_s_t_r_o_y_O_b_j deallocates all memory resources  associ-
            ated with the object pointed at by _O_b_j.  It works by calling
            _O_F_F_F_r_e_e_P_r_o_p_e_r_t_y for each property in the property  list  for
            the specified object.

                 _O_F_F_A_d_d_P_r_o_p_e_r_t_y adds a property structure  to  the  pro-
            perty  list  associated  with  the object pointed at by _O_b_j,
            initializes it, and returns  a  pointer  to  it.   The  null
            pointer is returned if the operation was unsuccessful.

                 _O_F_F_R_e_m_o_v_e_P_r_o_p_e_r_t_y deletes the named property  from  the
            object  pointed  at  by _O_b_j.  This routine returns -1 if the
            named property is not found in the  property  list  for  the
            specified object.

                 _O_F_F_F_r_e_e_P_r_o_p_e_r_t_y frees all the  memory  resources  allo-
            cated  to  the  property  structure specified by _P_r_o_p_e_r_t_y as
            well as the property structure itself.   This  routine  will
            not typically be called directly by applications.

            _7.  _O_b_j_e_c_t _S_e_a_r_c_h _P_a_t_h

                 It is important to avoid embedding path names in object
            files.   When  an  object  is transported to another system,
            chances are slim that  the  same  directory  structure  will
            exist.   The  _O_F_F_R_e_a_d_O_b_j  routine in libobj.a knows about an
            environment variable named _O_B_J__P_A_T_H that is used to overcome
            this problem.

                 When an object is read, an attempt  is  first  made  to
            open  it  in the current working directory.  If that attempt
            fails, the directories specified in the _O_B_J__P_A_T_H environment
            variable  are  tried  in turn until the file is successfully
            opened or the directory list is  exhausted.   _O_B_J__P_A_T_H  con-
            tains  a  list of directories, separated by spaces, that are
            to be searched for the named objects.

                 The name of  the  directory  where  a  successful  open
            operation occurred is used for opening associated data files
            as well.  This means that all of the data files for  a  par-
            ticular object must reside in the same directory.

                 It is hoped that in this way, users  will  be  able  to
            draw  on  one  or  more collections of "standard" objects in
            addition to their own private collections of objects.











                                   April 26, 1990






                                       - 15 -


            _8.  _A_p_p_e_n_d_i_x _A: _C_o_n_v_e_n_t_i_o_n_s _f_o_r _P_o_l_y_g_o_n_a_l _O_b_j_e_c_t_s

                 This list contains the conventions we have adopted  for
            describing  3D  polygonal  objects which are defined in some
            three-dimensional model coordinate system.  Items in regular
            type  are string literal, printed as they would appear in an
            OFF file, and item in italics indicate data values that will
            vary  from  object to object.  By convention, the header for
            an ASCII OFF file is suffixed with ".aoff"  and  the  header
            for  a  binary  OFF file is suffixed with ".off".  There are
            two choices for how colors  may  be  stored.   If  they  are
            stored as generic data, the suffixes used are ".{b}pcol" for
            polygon colors and ".{b}vcol" for vertex  colors.   If  they
            are   stored   as   indexed  data,  the  suffixes  used  are
            ".{b}ipcol" and ".{b}ivcol".


            box;                c|c|c|c|c|c                 l|l|l|l|l|l.
            Property        Type    Format  Defaults        ASCII
            filename  Binary                 Filename                  =
            name    *****   *****   _o_b_j_n_a_m_e *****   *****
            author  *****   *****   _a_u_t_h_o_r  *****   *****
            description     *****   *****   _d_e_s_c_r_i_p_t_i_o_n     *****   *****
            copyright       *****   *****   _c_o_p_y_r_i_g_h_t       *****   *****
            type    *****   *****   polyline        *****   *****
                    *****   *****   polygon *****   *****
            geometry        indexed_poly    fff     *****   _n_a_m_e.geom       _n_a_m_e.bgeom
            polygon_colors  generic fff     *****   _n_a_m_e.pcol       _n_a_m_e.bpcol
            vertex_colors   generic fff     *****   _n_a_m_e.vcol       _n_a_m_e.bvcol
            polygon_colors  indexed fff     *****   _n_a_m_e.ipcol      _n_a_m_e.bipcol
            vertex_colors   indexed fff     *****   _n_a_m_e.ivcol      _n_a_m_e.bivcol
            back_faces      default s       cull    *****   *****
                                    display *****   *****
                                    reverse *****   *****
            vertex_order    default s       clockwise       *****   *****
                                    counter-
            clockwise       *****   *****
                                    counterclock-
            wise        *****   *****
            polygon_normals generic fff     *****   _n_a_m_e.pnorm      _n_a_m_e.bpnorm
            vertex_normals  generic fff     *****   _n_a_m_e.vnorm      _n_a_m_e.bvnorm
            diffuse_coef    default f       _v_a_l_u_e   *****   *****
            specular_coef   default f       _v_a_l_u_e   *****   *****
            specular_power  default f       _v_a_l_u_e   *****   *****
            bounding_box    default ffffff  _v_a_l_u_e   *****   *****











                                   April 26, 1990






                                       - 16 -


            _9.  _A_p_p_e_n_d_i_x _B: _O_F_F _H_e_a_d_e_r _F_i_l_e _F_o_r _a _C_u_b_e (_c_u_b_e._a_o_f_f)








            ;    l    l.     name    cube    author  Randi    J.    Rost
            description     cube  with  sides of red, green, blue, cyan,
            yellow,      magenta      copyright       public      domain
            type    polygon


            ;  l  c  c  c  l  c  c  c   l   l   l   l.    #   Prop. data
            type       format  filename       or       default      data
            #_______        _________       ______  ________________________

            geometry        indexed_poly    fff     cube.geom
            vertex_order    default s       clockwise
            polygon_colors  generic fff     cube.pcol
            back_faces      default s       cull

































                                   April 26, 1990






                                       - 17 -


            _1_0.  _A_p_p_e_n_d_i_x _C: _L_i_s_t_i_n_g _o_f _c_u_b_e._g_e_o_m








            ;   nw(0.5i)   nw(0.5i)    nw(0.5i)    nw(0.5i)    nw(0.5i).
            8       6       24  -1.0    -1.0    1.0  -1.0    1.0     1.0
            1.0     1.0     1.0 1.0     -1.0    1.0 -1.0    -1.0    -1.0
            -1.0    1.0     -1.0  1.0     1.0     -1.0 1.0     -1.0    -
            1.0                        4       1       2       3       4
            4       5       6       2       1
            4       3       2       6       7
            4       3       7       8       4
            4       1       4       8       5
            4       8       7       6       5





































                                   April 26, 1990






                                       - 18 -


            _1_1.  _A_p_p_e_n_d_i_x _D: _L_i_s_t_i_n_g _o_f _c_u_b_e._p_c_o_l








            ; l s s nw(0.5i) nw(0.5i)  nw(0.5i).   6                 1.0
            0.0         0.0  0.0         1.0         0.0  0.0        0.0
            1.0 0.0        1.0        1.0 1.0        1.0        0.0  1.0
            0.0        1.0











































                                   April 26, 1990






                                       - 19 -


            _1_2.  _A_p_p_e_n_d_i_x _E: _L_i_s_t_i_n_g _o_f _o_f_f._h



            #define OFF_INDEXED_POLY_MAGIC  0xFEEDFEEDL
            #define OFF_GENERIC_MAGIC       0xBEEFBEEFL
            #define OFF_INDEXED_MAGIC       0xBADBADBAL

            #define OFF_BIGSTR              256
            #define OFF_SMSTR               40

            #define OFF_ASCII               0
            #define OFF_BINARY              1


            /* Types of data for object properties  */

            #define OFF_UNKNOWN_TYPE_DATA   0
            #define OFF_STANDARD_DATA       1
            #define OFF_COMMENT_DATA        2
            #define OFF_DEFAULT_DATA        3
            #define OFF_GENERIC_DATA        4
            #define OFF_INDEXED_POLY_DATA   5
            #define OFF_INDEXED_DATA        6


            typedef struct _OFFProp
                {
                char        PropName[OFF_SMSTR];     /* Name of property (or attribute)  */
                int         PropType;                /* Type of data for property        */
                char        PropFileName[OFF_BIGSTR];/* Name of file that has prop data  */
                char        DataFormat[OFF_SMSTR];   /* Pointer to property data format  */
                int         PropCount;               /* Number of data items for property*/
                char        *PropData;               /* Pointer to property data         */
                struct _OFFProp *NextProp;           /* Pointer to next property in list */
                } OFFProperty;

            typedef struct
                {
                OFFProperty *FirstProp;              /* Pointer to first property in list*/
                } OFFObjDesc;















                                   April 26, 1990






                                       - 20 -


            _1_3.  _A_p_p_e_n_d_i_x _F: _D_a_t_a _S_t_r_u_c_t_u_r_e _F_o_r_m_a_t

                 The following diagram depicts some of the  data  struc-
            tures   for   the  object  _c_u_b_e._a_o_f_f  after  being  read  by
            _O_F_F_R_e_a_d_O_b_j() (or just prior  to  being  written  by  _O_F_F_W_r_i_-
            _t_e_O_b_j()).  move to 0.0, 14.5 Object:         [         boxht
            = 0.3i; boxwid = 2.0i         moveht = 0.3i; movewid =  0.0i
                        down          A: box "FirstProp"            move
            up 0.3i; move right  2.0i              down          B:  box
                    ]

            move to 1.0, 13.0 Prop1:          [          boxht  =  0.3i;
            boxwid = 1.5i         moveht = 0.3i; movewid = 0.0i
            down         A: box "PropName"              down          B:
            box "PropType"            down         C: box "PropFileName"
                       down         D: box "DataFormat"             down
                    E:  box  "PropCount"             down         F: box
            "PropData"              down           H:   box   "NextProp"
                        move  up  2.1i;              move  right  2.25i;
                       boxht = 0.3i; boxwid = 3.0i             moveht  =
            0.3i;  movewid  = 0.0i            down         I: box "name"
                       down         J: box "OFF_STANDARD_DATA"
            down         K: box "_n_u_l_l _s_t_r_i_n_g"            down         L:
            box  "_n_u_l_l  _s_t_r_i_n_g"              down          M:  box   "0"
                        down          N:  box            down         O:
            box         ]

            move to 1.0, 10.0 Prop2:          [          boxht  =  0.3i;
            boxwid = 1.5i         moveht = 0.3i; movewid = 0.0i
            down         A: box "PropName"              down          B:
            box "PropType"            down         C: box "PropFileName"
                       down         D: box "DataFormat"             down
                    E:  box  "PropCount"             down         F: box
            "PropData"              down           H:   box   "NextProp"
                        move  up  2.1i;              move  right  2.25i;
                       boxht = 0.3i; boxwid = 3.0i             moveht  =
            0.3i; movewid = 0.0i            down         I: box "author"
                       down         J: box "OFF_STANDARD_DATA"
            down         K: box "_n_u_l_l _s_t_r_i_n_g"            down         L:
            box  "_n_u_l_l  _s_t_r_i_n_g"              down          M:  box   "0"
                        down          N:  box            down         O:
            box         ]

            move to 1.0, 7.0  Prop3:          [          boxht  =  0.3i;
            boxwid = 1.5i         moveht = 0.3i; movewid = 0.0i
            down         A: box "PropName"              down          B:
            box "PropType"            down         C: box "PropFileName"
                       down         D: box "DataFormat"             down
                    E:  box  "PropCount"             down         F: box
            "PropData"              down           H:   box   "NextProp"
                        move  up  2.1i;              move  right  2.25i;
                       boxht = 0.3i; boxwid = 3.0i             moveht  =




                                   April 26, 1990






                                       - 21 -


            0.3i;   movewid   =  0.0i              down          I:  box
            "geometry"                     down              J:      box
            "OFF_INDEXED_POLY_DATA"                down          K:  box
            "cube.geom"            down         L:  box  "fff"
            down          M:  box  "6"              down          N: box
                       down         O: box         ]

            move to 1.0, 4.0  Prop4:          [          boxht  =  0.3i;
            boxwid = 1.5i         moveht = 0.3i; movewid = 0.0i
            down         A: box "PropName"              down          B:
            box "PropType"            down         C: box "PropFileName"
                       down         D: box "DataFormat"             down
                    E:  box  "PropCount"             down         F: box
            "PropData"              down           H:   box   "NextProp"
                        move  up  2.1i;              move  right  2.25i;
                       boxht = 0.3i; boxwid = 3.0i             moveht  =
            0.3i;   movewid   =  0.0i              down          I:  box
            "polygon_colors"                  down            J:     box
            "OFF_GENERIC_DATA"                  down            K:   box
            "cube.pcol"            down         L:  box  "fff"
            down          M:  box  "6"              down          N: box
                       down         O: box         ]

            move to 1.0, 1.0  Prop5:          [          boxht  =  0.3i;
            boxwid = 1.5i         moveht = 0.3i; movewid = 0.0i
            down         A: box "PropName"              down          B:
            box "PropType"            down         C: box "PropFileName"
                       down         D: box "DataFormat"             down
                    E:  box  "PropCount"             down         F: box
            "PropData"              down           H:   box   "NextProp"
                        move  up  2.1i;              move  right  2.25i;
                       boxht = 0.3i; boxwid = 3.0i             moveht  =
            0.3i;   movewid   =  0.0i              down          I:  box
            "back_faces"                    down             J:      box
            "OFF_DEFAULT_DATA"              down          K:  box  "_n_u_l_l
            _s_t_r_i_n_g"            down         L: box "s"              down
                    M:  box  "0"            down         N: box
            down         O: box "_n_u_l_l _p_o_i_n_t_e_r"         ]

            line from Prop1.O.c to Prop1.O.c.x, (Prop1.s.y +  Prop2.n.y)
            /  2.0  line  to  0.5, (Prop1.s.y + Prop2.n.y) / 2.0 line to
            0.5, Prop2.A.c.y arrow to Prop2.A.w

            line from Prop2.O.c to Prop2.O.c.x, (Prop2.s.y +  Prop3.n.y)
            / 2.0 line to 0.5, (Prop2.s.y + Prop3.n.y) / 2.0 line dashed
            to 0.5, Prop3.A.c.y arrow to Prop3.A.w

            line from Prop3.O.c to Prop3.O.c.x, (Prop3.s.y +  Prop4.n.y)
            / 2.0 line to 0.5, (Prop3.s.y + Prop4.n.y) / 2.0 line dashed
            to 0.5, Prop4.A.c.y arrow to Prop4.A.w

            line from Prop4.O.c to Prop4.O.c.x, (Prop4.s.y +  Prop5.n.y)




                                   April 26, 1990






                                       - 22 -


            /  2.0  line  to  0.5, (Prop4.s.y + Prop5.n.y) / 2.0 line to
            0.5, Prop5.A.c.y arrow to Prop5.A.w

            line  from  Object.B.c  to   Object.B.c.x,   (Object.s.y   +
            Prop1.n.y) / 2.0 line to 0.5, (Object.s.y + Prop1.n.y) / 2.0
            line to 0.5, Prop1.A.c.y arrow to Prop1.A.w

            boxht = 0.3i; boxwid = 2.0i P1: box "cube" at Prop1.N.e.x  +
            1.5i, Prop1.N.e.y arrow from Prop1.N.c to P1.w

            P2: box "Randi J. Rost" at Prop2.N.e.x +  1.5i,  Prop2.N.e.y
            arrow from Prop2.N.c to P2.w

            P3: box "  8    6    24 -1.0 -1.0" at  Prop3.N.e.x  +  1.5i,
            Prop3.N.e.y  P4:  box " 1.0 -1.0  1.0  1.0  1.0" with .nw at
            P3.sw P5: box " 1.0  1.0  1.0 -1.0  1.0" with .nw  at  P4.sw
            P6: box "-1.0 -1.0 -1.0 -1.0  1.0" with .nw at P5.sw P7: box
            "-1.0  1.0  1.0 -1.0  1.0" with .nw at P6.sw P8:  box  "-1.0
            -1.0  4  4  4 4  4  4" with .nw at P7.sw P9: box "1  2  3  4
            5  6  2  1" with .nw at P8.sw Pa: box "3  2  6  7  3   7   8
            4"  with  .nw at P9.sw Pb: box "1  4  8  5  8  7  6  5" with
            .nw at Pa.sw arrow from Prop3.N.c to P3.w

            Pc: box "6    1.0  0.0  0.0  0.0"  at  Prop4.N.e.x  +  1.5i,
            Prop4.N.e.y  Pd:  box  "1.0  0.0  0.0  0.0  1.0" with .nw at
            Pc.sw Pe: box "0.0  1.0  1.0  1.0  1.0" with  .nw  at  Pd.sw
            Pf:  box  "0.0   1.0  0.0  1.0     " with .nw at Pe.sw arrow
            from Prop4.N.c to Pc.w

            boxht = 0.3i; boxwid = 0.5i Pg: box at Prop5.N.e.x  +  1.0i,
            Prop5.N.e.y  Ph:  box  "cull"  at Pg.e.x + 1.0i, Prop5.N.e.y
            arrow from Pg.c to Ph.w arrow from Prop5.N.c to Pg.w

            "Object" at Object.A.n above






















                                   April 26, 1990






                                       - 23 -


            _1_4.  _A_c_k_n_o_w_l_e_d_g_e_m_e_n_t_s

                 OFF is a derivative of an object file  format  used  at
            Ohio  State University.  Special thanks to Allen Akin of WSE
            for helpful ideas  and  suggestions.  Thanks  also  to  Jeff
            Friedberg  of  Digital's High-Performance Workstation (HPWS)
            group and Shaun Ho  of  WSE  who  also  contributed  to  the
            design.  Danny Shapiro of WSE provided suggestions for addi-
            tional enhancements and conventions.















































                                   April 26, 1990