textfiles/programming/FORMATS/off.txt

1519 lines
60 KiB
Plaintext
Raw Permalink Normal View History

2021-04-15 11:31:59 -07:00
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