You can create a node using CreateParse
constructor to parse the node. Or you can initialize node
contents by parsing it using Parse
method.
However, these both approaches require you to
first prepare appropriate TX3DLexer
instance and a list of read node names.
There are comfortable routines like ParseVRMLFile
that take care of this for you. They create appropriate lexer,
and may create also suitable TStream
instance to read
given file content.
Some details about parsing:
Our VRML/X3D lexer is a unified lexer for both VRML 1.0, 2.0 and (classic) X3D. Most of the syntax is identical, minor differences can be handled correctly by a lexer because it always knows VRML/X3D header line of the given file. So it knows what syntax to expect.
VRML/X3D version of the original file is saved in
TVRMLRootNode.ForceVersion
. This will be used later when saving. Parser always returnsTVRMLRootNode
instance, this keeps some per-file settings like version and X3D profile, components and meta values.When saving, you can save any
TVRMLNode
instance to file. If it is notTVRMLRootNode
, or ifTVRMLRootNode.HasForceVersion
is false, we simply assume it uses the latest X3D version.In engine versions <= 2.5.0 we experimented with auto-detecting the suitable VRML/X3D version for nodes inside, but this mechanism was dropped. It was complicated, and was failing anyway for complicated cases (nodes from mixed versions, things with routes, imports, exports etc.). If you want to save a specific VRML/X3D version, it's best to simply wrap it inside
TVRMLRootNode
and force desired version explicitly. Modern programs should target only X3D anyway, as VRML 1.0 is ancient, and VRML 2.0 is old too (from 1997).While parsing,
ForVRMLVersion
method mentioned earlier may be used to decide which node classes to create based on VRML/X3D version indicated in the file's header line.To properly handle DEF / USE mechanism we keep a list of known node names while parsing. After a node with
DEF
clause is parsed we add the node name and it's reference toNodeNameBinding
list that is passed through all parse routines. When aUSE
clause is encountered, we just search this list for appropriate node name.Simple VRML rules of
DEF
/USE
behavior make this approach correct. Remember that VRML name scope is not modeled after normal programming languages, where name scope of an identifier is usually limited to the structure (function, class, etc.) where this identifier is declared. In VRML, name scope always spans to the end of whole VRML file (or to the nextDEF
occurrence with the same name, that overrides previous name). Also, the name scope is always limited to the current file — for example, you cannot use names defined in other VRML files (that you included byInline
nodes, or that include you). (Prototypes and external prototypes in VRML 2.0 are designed to allow reusing VRML code between different VRML files.)The simple trick with adding our name to
NodeNameBinding
after the node is fully parsed prevents creating loops in our graph, in case supplied VRML file is invalid.