How to Write an IRIS Inventor File Translator

Release 1.0

Section 5 File Format Syntax

This section outlines details of the syntax for the Inventor ASCII file format. Inventor's file format ignores extra white space created by spaces, tabs, and new lines (except within quoted strings). Comments begin with a number sign (#) anywhere on a line and continue to the end of the line:

# this is a comment in the Inventor file format

See the IRIS Inventor Nodes Quick Reference for individual descriptions of the file format for each Inventor class.

5.1 File Header
Every Inventor data file must have a standard header to identify it. This header has the following form:

#Inventor V1.0 ascii


#Inventor V1.0 binary

To determine whether a file is an Inventor file or not, use the SoDB::isValidHeader() method and pass in the first line of the file in question. Although the header may change from version to version, it is guaranteed that it will begin with a # sign, will be no more than 80 characters, and will end at a newline. Therefore, the C fgets() routine can be used. The isValidHeader() method returns TRUE if the file contains an Inventor header.

An example of using fgets() to check the header is

FILE *fp = fopen ( filename, "r" );
char headerString [80];
fgets( headerString, 80, fp );

if( SoDB::isValidHeader( headerString ))
   printf( "File has valid Inventor header\n");
   printf( "Invalid Inventor header\n");
5.2 Writing a Node
A node is written as:

nodename {
      field1name   value
      field2name    value
      [child nodes]
      [ . . . ]

For example:

DrawStyle {
	style		LINES
	lineWidth	3
	linePattern	0x00ff

5.3 Writing Values within a Field
Fields within a node are written as the name of the field, followed by the value or values contained in the field. If the field value has not been changed from its default value, that field is not written out. Fields within a node can be written in any order. An example of writing field values is

Transform {
	translation	0 -4 0.2

LightModel {
	model		BASE_COLOR

Use brackets to surround multiple-value elds, with commas separating the values, as shown below for the diffuseColor field. It's all right to have a comma after the last value as well:

[ value1, value2, value3, ]

For example:

Material {
	ambientColor	.3 .1 .1
	diffuseColor   [.8 .7 .2,
			 1 .2 .2,
			.2  1 .2,
			.2 .2  1]
	specularColor	.4 .3 .1
	emissiveColor	.1  0 .1

Single-value fields (SF) do not contain any brackets or commas. Multiple-value fields (MF) usually have brackets, but they are not necessary if only one value is present:

specularColor .4 .3 .1


specularColor [.4 .3 .1 ]

The value that is written depends on the type of the field, as follows:

Type of Field		Acceptable Formats

longs, shorts,		integers
unsigned shorts

floats			integer or floating point number. For example:

names, strings		double quotation marks (" ") around the name if it is more than
			one word, or just the name (with no white space) if it is a single
			word. For example:

			label	" front left leg "
			label	car

			You can have any character in the string, including newlines and
			backslashes, except for double quotation marks. To include a double
			quotation mark in the string, precede it with a backslash (\").

enums			either the mnemonic form of the enum or the integer equivalent.
			(The mnemonic form is recommended, both for portability and
			readability of les.) For example:

			MaterialBinding {
				value	PER_FACE

bit mask		one or more mnemonic ags, separated by a vertical bar (|) if there
			are multiple ags. When more than one ag is used, parentheses are

			Cylinder {
				parts	SIDES

			Cylinder {
				parts	(SIDES | TOP)

vectors			n floats separated by white space:
(SbVecnf, where n is
the number of		PerspectiveCamera {
components of the		position	0 0 9.5
vector)			}

colors			3 floats (RGB) separated by white space:

			BaseColor {
				rgb	0.3 0.2 0.6

rotation		a 3-vector of oats for the axis, followed by a oat for the angle (in
			radians), separated by white space:

			Transform {
				rotation	0 1 0       1.5708
          					# y axis ... PI/2 radians

matrix			16 floats, separated by white space (row major order)

path			An SoSFPath has one value, a pointer to a path. To write this
			value, write the path (see Section 12.3.5 of the Inventor
			Programming Guide, Volume I). An SoMFPath has multiple
			values, which are all pointers to paths. To write this value, enclose
			the path list in brackets, and use commas to separate each path:

			[ first_path, second_path, ... nth_path ]

node			An SoSFNode has one value, a pointer to a node. To write this
			value, write the node using the standard format for all nodes. An
			SoMFNode has multiple values, which are all pointers to nodes. To
			write this value, enclose the node list in brackets, and use commas to
			separate each node:

			[ node1, node2, ... noden ]

5.4 Ignore Flag
The ignore flag for a node (see Chapter 3 of the Inventor Programming Guide, Volume I) is written as a tilde ( ~ ), either after or in place of the field value or values. For example:

transparency [ .9, .1 ] ~


transparency ~

The first case preserves the values even though the field is ignored. The second case uses the default value but ignores the field.

5.5 Sample Scene Graph and Inventor File
Here is the file for a sample scene graph, which creates chartreuse, rust, and violet wireframe spheres. Figure 13 shows the scene graph for this file.

Separator {
	PerspectiveCamera {
		position 0 0 9.53374
		aspectRatio 1.09446
		nearDistance 0.0953375
		farDistance 19.0675
		focalDistance 9.53374
	DirectionalLight { }     # note:  default fields for this light
	Transform {
		rotation -0.189479 0.981839 -0.00950093 0.102051
		center 0 0 0
	DrawStyle {
		style  LINES
	Separator {
		LightModel {
			model BASE_COLOR
		Separator {
			Transform {
				translation -2.2 0 0
			BaseColor {
				rgb .2 .6 .3	# chartreuse
			Sphere { }
		Separator {
			BaseColor {
				rgb .6 .3 .2	# rust
			Sphere { }
		Separator {
			Transform {
				translation 2.2 0 0
			BaseColor {
				rgb .3 .2 .6	# violet
			Sphere { }
Figure 13 Scene graph for a scene with three spheres

5.6 Instancing
When a scene graph contains shared instances of a node, Inventor defines a temporary name for the node and uses that name when writing subsequent occurrences of that node in the scene graph. It inserts the letters DEF (for define), followed by the name for the first use of the node. Thereafter, Inventor simply writes USE plus the name defined for that node.

For example, the scene graph shown in Figure 14 would be written as follows (without the comments):

Group {				# group A
	Group {			# group B
		DEF d Cube { }	# define D and use it
	Group {			# group C
		USE  d		# use D again

Figure 14 Defining a node for multiple uses

Inventor uses this DEF/USE technique for paths as well as for nodes. For les to be read into Inventor, the name for a node or path can be any valid identifier. This name is thrown away after the file is read. (Identifiers start with an underscore or a letter and must consist entirely of letters, numbers, and underscores.) Names used within a file must be unique. A name can, however, be used in multiple les, since each file maintains its own list of names.

5.7 Including Other Files
To include a file within another le, use an SoFile node. This node is written as

File {
	name "myFile.iv"

where the name field is the name of the file to be included. The contents of the file myFile.iv are added as children of SoFile.

The SoFile node has an associated WriteBack flag. If this flag is TRUE (the default), then the children of SoFile are written back to their original file if anything below the SoFile node changed. If this flag is FALSE, then the original file remains untouched, even if changes occurred to the sub-graph below the node. Use the setWriteBack() and getWriteBack() methods to change the value of this ag and to obtain its current value. If the file cannot be written, Inventor prints a warning.

5.8 ASCII and Binary Versions
The SoOutput object in an SoWriteAction has a setBinary() method, which sets whether the output should be in ASCII (default) or binary format. The getOutput() method returns a pointer to the SoOutput. When a file is written, Inventor inserts a header line that indicates whether the file is in ASCII or binary format, as well as the Inventor version number.

For example, to write in ASCII to a file:

SoWriteAction w;

w.getOutput()->setBinary( FALSE );
if ( w.getOutput()->openFile( "myFile.iv" )) {
	w.apply( root );