NEW for 1.1 - Prototyping

TODO: Gavin to make minor edits

Prototyping is a mechanism that allows the set of node types to be extended from within a VRML file. A prototype is defined using the PROTO keyword, as follows:

PROTO typename [ input fieldtypename name IS nodename.fieldname,
                 output fieldtypename name IS nodename.outputname,
                 ... ]
      node { ... }

A prototype is NOT a node; it merely defines a prototype (named 'typename') that can be used later in the same file as if it were a built-in node. The implementation of the prototype is contained in the scene graph rooted by node. The implemenation may not be DEF'ed or USE'ed.

The input and output declarations export inputs and outputs inside the scene graph given by node. Specifying the type of each input or output in the prototype is intended to prevent errors when the implementation of prototypes are changed, and to provide consistency with external prototypes. Specifying a name for each input or output allows several inputs or outputs with the same name to be exported with unique names. Prototypes do not have fields, and fields inside the implementation may not be exported (only inputs and outputs).

The node names specified in the input and output declarations must be DEF'ed inside the prototype implementation. The first node DEF'ed in lexical (not traversal) order will be exported. It is an error (and results are undefined) if there is no node with the given name, or the first node found does not contain a field of the appropriate type with the given field name.

Prototype declarations have file scope, and prototype names must be unique in any given file.

A prototype is instantiated as if typename were a built-in node. A prototype instance may be DEF'ed or USE'ed. For example, a simple chair with variable colors for the leg and set might be prototyped as:

PROTO twoColorChair [ input SFColor legColor IS leg.diffuseColor,
        input SFColor seatColor IS seat.diffuseColor ]
     Separator {
        Separator {
            DEF seat DynamicMaterial { }
            Cube { ... }
        }
        Separator {
            Transform { ... }
            DEF leg DynamicMaterial { }
            Cylinder { ... }
        }
    }
# Prototype is now defined.  Can be used like:
DEF redGreenChair twoColorChair { legColor 1 0 0  seatColor 0 1 0 }

USE redGreenChair # Regular DEF/USE rules apply

Issue: Can we pass in "plug-in" scene graphs using input SFNode ...? Should we extend USE to handle USE prototypename.inputname? If so, what happens if that input isn't specified?

Issue: definition of legal node type names is never specified. Should they be same a legal node names?

Note: PROTO sort of gives people their non-instantiating DEF: PROTO foo [] Cube { } is roughly equal to DEF foo Cube { }, except that foo is now a type name instead of an instance name (and you say foo { } to get another cube instead of USE foo). Smart implementations will automatically share the unchanging stuff in prototype implementations, so the end result will be the same.

A second form of the prototype syntax allows prototypes to be defined in external files:

EXTERNPROTO typename [ input fieldtypename name,
                       output fieldtypename name, ... ]
            URL

In this case, the implementation of the prototype is found in the given URL. The file pointed to by that URL must contain ONLY a single prototype implementation (using PROTO). That prototype is then given the name typename in this file's scope (allowing possible naming clashes to be avoided). It is an error if the input/output declaration in the EXTERNPROTO is not a subset of the input/output declaration specified in URL.

Note: The rules about allowing exporting only from files that contain a single PROTO declaration are consistent with the WWWInline rules; until we have VRML-aware protocols that can send just one object or prototype declaration across the wire, I don't think we should encourage people to put multiple objects or prototype declarations in a single file.