Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > by-pkgid > 052d79447130ebaf90b2730395954d11 > files > 952

openvrml-doc-0.18.3-1mdv2010.0.i586.rpm

<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
               "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>OpenVRML: 2 Parsing VRML97 and VRML-encoded X3D</title>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<link rel="icon" href="../vrml-16">
<link rel="start" href="http://openvrml.org/index" title="OpenVRML Home">
<link rel="prev" href="http://openvrml.org/discussion" title="Discussion">
<link rel="contents" href="index" title="Documentation Main Page">
<link rel="index" href="functions" title="OpenVRML Compound Members">
<link rel="appendix" href="conformance" title="Conformance Test Results">
<style type="text/css">
@import url("tabs.css");
@import url("http://openvrml.org/openvrml.css");

table {
  width: 100%;
}

h2 {
  border-bottom-style: solid;
  border-bottom-width: 1px;
}

/*
 * Doxygen as of 1.5.4-20071217 uses the class "navpath" instead of "nav".
 * For now, we'll do both.
 */

div.nav,
div.navpath {
  background-color: transparent;
  text-align: left;
  margin-top: 1em;
  margin-bottom: 1em;
  border-color: black;
  border-left: none;
  border-right: none;
  padding-top: 0.5em;
  padding-bottom: 0.5em;
}

div.nav :link, div.nav :visited,
div.navpath :link, div.navpath :visited {
  border-width: 1px;
  border-style: solid;
  border-color: silver;
  padding: 2px;
}

div.nav :link:hover, div.nav :visited:hover,
div.navpath :link:hover, div.navpath :visited:hover {
  border-style: outset;
  border-color: gray;
}

div.nav :active,
div.navpath :active {
  border-style: inset;
  border-color: gray;
}

.body td {
  background-color: transparent;
}

.el {
  text-decoration: inherit;
  font-weight: inherit
}
.elRef {
  font-weight: inherit
}
.code:link, .code:visited {
  text-decoration: inherit;
  font-weight: inherit;
  color: inherit;
}
.codeRef:link {
  font-weight: normal;
  color: inherit;
}
:visited {
  color: silver;
}
:link:hover {
  color: inherit;
  text-decoration: inherit;
  background-color: transparent;
}

h1 {
  line-height: 1.2em;
}

td.memItemLeft, td.memItemRight,
td.memTemplParams, td.memTemplItemLeft, td.memTemplItemRight,
.memtemplate, .memname td {
  font-family: Consolas, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Lucida Console", LucidaTypewriter, monospace;
}

td.memItemLeft, td.memItemRight, td.mdescLeft, td.mdescRight {
  background-color: rgb(95%, 95%, 95%);
  border-color: rgb(65%, 65%, 65%);
  border-width: 1px;
  font-size: smaller;
}

.memItemLeft {
  margin-top: 0.5em;
  border-top-style: solid;
}
.mdescLeft {
  border-bottom-style: solid;
}
.memItemRight {
  border-top-style: solid;
  margin-top: 0.5em;
}
.mdescRight {
  border-bottom-style: solid;
}

.mdescRight {
  font-style: italic;
}

.mdTable {
  background-color: rgb(95%, 95%, 95%);
}

.memproto td code {
  font-family: inherit;
  font-style: italic;
}

td.pass {
  background-color: rgb(50%, 100%, 50%);
}

td.fail {
  background-color: rgb(100%, 50%, 50%);
}

td.invalid {
  background-color: rgb(75%, 75%, 75%);
}

.memitem {
  padding: 0;
}

.memitem table {
  width: auto;
}

.memproto, .memdoc {
  border-width: 1px;
  border-color: rgb(65%, 65%, 65%);
}

.memproto {
  background-color: rgb(90%, 90%, 90%);
  font-weight: inherit;
  font-size: smaller;
  border-top-style: solid;
  border-left-style: solid;
  border-right-style: solid;
  -webkit-border-top-left-radius: 0.6em;
  -webkit-border-top-right-radius: 0.6em;
  -moz-border-radius-topleft: 0.6em;
  -moz-border-radius-topright: 0.6em;
}

.memdoc {
  background-color: rgb(95%, 95%, 95%);
  padding: 2px 5px;
  border-style: solid;
  -webkit-border-bottom-left-radius: 0.6em;
  -webkit-border-bottom-right-radius: 0.6em;
  -moz-border-radius-bottomleft: 0.6em;
  -moz-border-radius-bottomright: 0.6em;
}

.memname {
  font-weight: inherit;
}

div.tabs {
  background-image: url("tab_b-openvrml.png");
}

div.tabs span {
  background-image: url("tab_l-openvrml.png");
}

div.tabs a {
  background-image: url("tab_r-openvrml.png");
  border-bottom: 1px solid #a5a5a5;
}

div.tabs a:link, div.tabs a:visited, div.tabs a:active, div.tabs a:hover {
  color: black;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

.note {
  border: 1px solid rgb(65%, 65%, 65%);
  background-color: rgb(95%, 95%, 95%);
  margin-left: 10%;
  margin-right: 10%;
}
</style>
</head>
<body>
<table class="sitenav">
  <tr>
    <th><a href="http://openvrml.org/index" title="Home">Home</a></th>
    <th><a href="http://openvrml.org/download" title="Download">Download</a></th>
    <th><a href="http://openvrml.org/screenshots/index" title="Screen shots">Screen shots</a></th>
    <th><a href="http://openvrml.org/discussion" title="Mailing lists and IRC">Discussion</a></th>
    <th>Documentation</th>
  </tr>
</table>
<div class="body">
<!-- Generated by Doxygen 1.5.8 -->
<div class="navigation" id="top">
  <div class="tabs">
    <ul>
      <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
      <li class="current"><a href="pages.html"><span>Related&nbsp;Pages</span></a></li>
      <li><a href="namespaces.html"><span>Namespaces</span></a></li>
      <li><a href="annotated.html"><span>Classes</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
      <li><a href="examples.html"><span>Examples</span></a></li>
    </ul>
  </div>
  <div class="navpath"><a class="el" href="index.html">OpenVRML User's Guide</a>
  </div>
</div>
<div class="contents">
<h1><a class="anchor" name="parsing">2 Parsing VRML97 and VRML-encoded X3D </a></h1>OpenVRML includes parsers for reading VRML97 and VRML-encoded X3D. Prior to version 0.17.0, users wanting to use OpenVRML to load VRML or X3D had to load the file into an <code><a class="el" href="classopenvrml_1_1browser.html" title="Encapsulates a VRML browser.">openvrml::browser</a></code> and traverse the runtime's scene hierarchy. While this approach is still possible, OpenVRML now provides parsers that can be used separately from <code><a class="el" href="classopenvrml_1_1browser.html" title="Encapsulates a VRML browser.">openvrml::browser</a></code>. Using these parsers directly is more efficient since the OpenVRML runtime machinery doesn't need to be started. And it many cases, it will also be easier to implement. These parsers are implemented using the <a href="http://spirit.sourceforge.net">Spirit parsing framework</a> and have the following features:<p>
<ul>
<li>The parsers are largely self-contained. They depend on libopenvrml for node type definitions, but little else. In the future it is likely that the parsers' mechanism for getting node type information will be exposed and made user-replaceable.</li><li>The parsers are strict. Invalid code gets rejected. The parsers have been constructed to be appropriate for ensuring syntactic and semantic correctness of the parsed stream.</li><li>The parsers work with arbitrary user-supplied semantic actions.</li></ul>
<h2><a class="anchor" name="using_spirit_parsers">
2.1 Using Spirit parsers</a></h2>
Spirit is a framework of C++ templates that facilitates parser creation directly in C++ using a <a href="http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form">BNF</a>-like syntax. Using Spirit, you can create simple parsers for fragments of syntax and combine them to create sophisticated parsers for complete grammars. Such grammar parsers are typically packaged in a class (or class template) called a &ldquo;grammar capsule&rdquo;. <code><a class="el" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar</a></code> and <code><a class="el" href="structopenvrml_1_1x3d__vrml__grammar.html" title="A Spirit grammar for parsing Classic VRML X3D.">openvrml::x3d_vrml_grammar</a></code> are such grammar capsules.<p>
Grammar capsules are a particular form of Spirit parser. A Spirit parser is a protocol (or &ldquo;concept&rdquo;); that is, it is a set of lexical requirements to which a type must conform. Those requirements are detailed in the Spirit documentation; for our purposes, what's important is that Spirit parsers are things that can be used with Spirit's <code>parse</code> function template:<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">namespace </span>boost {
   <span class="keyword">namespace </span>spirit {
     <span class="keyword">namespace </span>classic {
       <span class="keyword">template</span> &lt;<span class="keyword">typename</span> IteratorT, <span class="keyword">typename</span> ParserT, <span class="keyword">typename</span> SkipT&gt;
       parse_info&lt;IteratorT&gt;
       parse(<span class="keyword">const</span> IteratorT &amp;       first,
             <span class="keyword">const</span> IteratorT &amp;       last,
             <span class="keyword">const</span> parser&lt;ParserT&gt; &amp; p,
             <span class="keyword">const</span> parser&lt;SkipT&gt; &amp;   skip);
     }
   }
 }
</pre></div><p>
In a pattern that should be familiar to users of the C++ standard library, <code>parse</code> accepts a pair of iterators that denote the range of data to operate on. This function is used as follows:<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">using</span> boost::spirit::classic::parse;

 std::vector&lt;char&gt; my_data;
 my_skip_parser my_skip;
 my_grammar my_g;

 <span class="keywordflow">if</span> (!parse(my_data.begin(), my_data.end(), my_g, my_skip).full) {
     <span class="keywordflow">return</span> EXIT_FAILURE;
 }
</pre></div><p>
In the above example, we are checking the <code>full</code> member of the <code>parse_info&lt;IteratorT&gt;</code> struct that <code>parse</code> returns; <code>full</code> is <code>true</code> in the case of a &ldquo;full match&rdquo;, and <code>false</code> otherwise.<p>
The other part of this example which we've glossed over until now is the &ldquo;skip parser&rdquo;, <code>my_skip</code>. Spirit uses the skip parser to identify text that should be discarded prior to parsing: typically, whitespace and comments. <code><a class="el" href="structopenvrml_1_1vrml97__skip__grammar.html" title="A Spirit grammar appropriate for use as a skip parser for VRML97 and VRML-encoded...">openvrml::vrml97_skip_grammar</a></code> is a skip parser appropriate for use with VRML97 and Classic VRML X3D.<p>
<dl class="note" compact><dt><b>Note:</b></dt><dd>X3D&nbsp;3.2 introduces a block comment syntax to the Classic VRML encoding. OpenVRML does not yet include a skip parser capable of parsing these comments.</dd></dl>
<h2><a class="anchor" name="position_iterator">
2.2 position_iterator</a></h2>
Substituting a few elements of the example, we're well on our way to something that actually parses VRML:<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">using</span> boost::spirit::classic::parse;

 std::string my_data = <span class="stringliteral">"#VRML 2.0 utf8\n"</span>
                       <span class="stringliteral">"Group {}\n"</span>;
 <a class="code" href="structopenvrml_1_1vrml97__skip__grammar.html" title="A Spirit grammar appropriate for use as a skip parser for VRML97 and VRML-encoded...">openvrml::vrml97_skip_grammar</a> my_skip;
 <a class="code" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar&lt;&gt;</a> my_g;

 <span class="keywordflow">if</span> (!parse(my_data.begin(), my_data.end(), my_g, my_skip).full) {
     <span class="keywordflow">return</span> EXIT_FAILURE;
 }
</pre></div><p>
There's just one more critical thing missing from the above example. This code is using the default error handler. (Error handlers are covered in detail in <a class="el" href="parsing.html#error_handling">2.5 Error handling</a>.) The default error handler requires that the iterators used for parsing be <code>position_iterators</code>.<p>
The <code>position_iterator</code> keeps track of positional information; and the default error handler uses this information to emit error messages that include the file name and line and column numbers. The <code>position_iterator</code> works as an adapter for an existing iterator type:<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> # include &lt;<a class="code" href="vrml97__grammar_8h.html" title="VRML97 Spirit grammar and associated parsers.">openvrml/vrml97_grammar.h</a>&gt;</span>

 <span class="keywordtype">int</span> main()
 {
     <span class="keyword">using</span> boost::spirit::classic::parse;
     <span class="keyword">using</span> boost::spirit::classic::position_iterator;

     std::string my_data = <span class="stringliteral">"#VRML 2.0 utf8\n"</span>
                           <span class="stringliteral">"Group {}\n"</span>;
     <a class="code" href="structopenvrml_1_1vrml97__skip__grammar.html" title="A Spirit grammar appropriate for use as a skip parser for VRML97 and VRML-encoded...">openvrml::vrml97_skip_grammar</a> my_skip;
     <a class="code" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar&lt;&gt;</a> my_g;

     <span class="keyword">typedef</span> position_iterator&lt;std::string::iterator&gt; iterator_t;

     iterator_t first(my_data.begin(), my_data.end(), <span class="stringliteral">"vrmlstring"</span>), last;

     <span class="keywordflow">if</span> (!parse(first, last, my_g, my_skip).full) {
         <span class="keywordflow">return</span> EXIT_FAILURE;
     }
     <span class="keywordflow">return</span> EXIT_SUCCESS;
 }
</pre></div><p>
The beginning <code>position_iterator</code> takes three arguments: the first two are the beginning and ending underlying iterators; the last is a string that will be used as the file name. Since we aren't parsing an actual file here, <code>"vrmlstring"</code> is used for the third argument.<p>
The ending <code>position_iterator</code> is simply a default-constructed one.<h2><a class="anchor" name="parsing_streams">
2.3 Parsing streams</a></h2>
The previous examples demonstrated parsing text in a <code>std::vector</code> or a <code>std::string</code>; and while such an approach is sometimes useful, more commonly one is interested in parsing the contents of a stream.<p>
Due to Spirit's requirements to support backtracking, it is not possible simply to hand the <code>parse</code> function an input iterator like <code>std::istreambuf_iterator</code>. Instead, Spirit provides an iterator adapter called <code>multi_pass</code> that can work with such iterators.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> # include &lt;<a class="code" href="vrml97__grammar_8h.html" title="VRML97 Spirit grammar and associated parsers.">openvrml/vrml97_grammar.h</a>&gt;</span>

 <span class="keywordtype">int</span> main()
 {
     <span class="keyword">using</span> std::istreambuf_iterator;
     <span class="keyword">using</span> boost::spirit::classic::parse;
     <span class="keyword">using</span> boost::spirit::classic::position_iterator;
     <span class="keyword">using</span> boost::spirit::classic::multi_pass;
     <span class="keyword">using</span> boost::spirit::classic::make_multi_pass;

     <span class="keyword">typedef</span> multi_pass&lt;istreambuf_iterator&lt;char&gt; &gt; multi_pass_iterator_t;

     multi_pass_iterator_t
         in_begin(make_multi_pass(istreambuf_iterator&lt;char&gt;(std::cin))),
         in_end(make_multi_pass(istreambuf_iterator&lt;char&gt;()));

     <span class="keyword">typedef</span> position_iterator&lt;multi_pass_iterator_t&gt; iterator_t;

     iterator_t first(in_begin, in_end, <span class="stringliteral">"&lt;stdin&gt;"</span>), last;

     <a class="code" href="structopenvrml_1_1vrml97__skip__grammar.html" title="A Spirit grammar appropriate for use as a skip parser for VRML97 and VRML-encoded...">openvrml::vrml97_skip_grammar</a> my_skip;
     <a class="code" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar&lt;&gt;</a> my_g;

     <span class="keywordflow">if</span> (!parse(first, last, my_g, my_skip).full) {
         <span class="keywordflow">return</span> EXIT_FAILURE;
     }
     <span class="keywordflow">return</span> EXIT_SUCCESS;
 }
</pre></div><p>
Here, we wrap an <code>istreambuf_iterator</code> in a <code>multi_pass</code> iterator, and then wrap that in a <code>position_iterator</code>. Once we have the <code>position_iterators</code>, we pass them to <code>parse</code> exactly as before.<p>
The above example, when compiled, will parse VRML97 from standard input.<h2><a class="anchor" name="semantic_actions">
2.4 Semantic actions</a></h2>
Semantic actions are how the parsing process delivers data to user code.<p>
<code><a class="el" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar</a></code> and <code><a class="el" href="structopenvrml_1_1x3d__vrml__grammar.html" title="A Spirit grammar for parsing Classic VRML X3D.">openvrml::x3d_vrml_grammar</a></code> are in fact class templates; though in the examples up to now we've simply relied on the default values for their template arguments. These templates take two arguments: <code>Actions</code> and <code>ErrorHandler</code>. The second of these arguments is addressed in the next section, <a class="el" href="parsing.html#error_handling">2.5 Error handling</a>. The first is an object the bundles the semantic actions to be executed during the parse.<p>
<code>Actions</code> is a <code>struct</code> that contains semantic actions in the form of function objects. The default value of the <code>Actions</code> template parameter is <code><a class="el" href="structopenvrml_1_1null__vrml97__parse__actions.html" title="No-op semantic actions for vrml97_grammar.">openvrml::null_vrml97_parse_actions</a></code> for <code><a class="el" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar</a></code>, and <code><a class="el" href="structopenvrml_1_1null__x3d__vrml__parse__actions.html" title="No-op semantic actions for x3d_vrml_grammar.">openvrml::null_x3d_vrml_parse_actions</a></code> for <code><a class="el" href="structopenvrml_1_1x3d__vrml__grammar.html" title="A Spirit grammar for parsing Classic VRML X3D.">openvrml::x3d_vrml_grammar</a></code>. These &ldquo;null&rdquo; parse actions <code>structs</code> provide a no-op function for each semantic action invoked by the respective grammar. You can inherit these in your own semantic actions <code>struct</code> to avoid having to define a function object for every action yourself.<p>
The following example expands on our existing one to add a semantic action that simply prints the node types of encountered nodes to the standard output.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> # include &lt;iostream&gt;</span>
<span class="preprocessor"> # include &lt;<a class="code" href="vrml97__grammar_8h.html" title="VRML97 Spirit grammar and associated parsers.">openvrml/vrml97_grammar.h</a>&gt;</span>

 <span class="keyword">struct </span>actions : openvrml::null_vrml97_parse_actions {
     <span class="keyword">struct </span>on_node_start_t {
         <span class="keywordtype">void</span> operator()(<span class="keyword">const</span> std::string &amp; node_name_id,
                         <span class="keyword">const</span> std::string &amp; node_type_id)<span class="keyword"> const</span>
<span class="keyword">         </span>{
             std::cout &lt;&lt; node_type_id &lt;&lt; std::endl;
         }
     } on_node_start;
 };

 <span class="keywordtype">int</span> main()
 {
     <span class="keyword">using</span> std::istreambuf_iterator;
     <span class="keyword">using</span> boost::spirit::classic::parse;
     <span class="keyword">using</span> boost::spirit::classic::position_iterator;
     <span class="keyword">using</span> boost::spirit::classic::multi_pass;
     <span class="keyword">using</span> boost::spirit::classic::make_multi_pass;

     <span class="keyword">typedef</span> multi_pass&lt;istreambuf_iterator&lt;char&gt; &gt; multi_pass_iterator_t;

     multi_pass_iterator_t
         in_begin(make_multi_pass(istreambuf_iterator&lt;char&gt;(std::cin))),
         in_end(make_multi_pass(istreambuf_iterator&lt;char&gt;()));

     <span class="keyword">typedef</span> position_iterator&lt;multi_pass_iterator_t&gt; iterator_t;

     iterator_t first(in_begin, in_end, <span class="stringliteral">"&lt;stdin&gt;"</span>), last;

     <a class="code" href="structopenvrml_1_1vrml97__skip__grammar.html" title="A Spirit grammar appropriate for use as a skip parser for VRML97 and VRML-encoded...">openvrml::vrml97_skip_grammar</a> my_skip;
     actions my_actions;
     <a class="code" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar&lt;actions&gt;</a> my_g(my_actions);

     <span class="keywordflow">if</span> (!parse(first, last, my_g, my_skip).full) {
         <span class="keywordflow">return</span> EXIT_FAILURE;
     }
     <span class="keywordflow">return</span> EXIT_SUCCESS;
 }
</pre></div><p>
The <code><a class="el" href="pretty__print_8cpp-example.html">pretty_print.cpp</a></code> example program provides a more thorough demonstration of the semantic action facility.<h2><a class="anchor" name="error_handling">
2.5 Error handling</a></h2>
By default, the parsers emit error and warning messages to <code>stderr</code>. Where messages are printed (if they are printed at all) and how the parsers respond to errors is controlled using a Spirit error handler.<p>
As mentioned in the previous section, the second template argument to the grammar class templates is an <code>ErrorHandler</code>. The <code>ErrorHandler</code> is a function object of the form:<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>error_handler {
     <span class="keyword">template</span> &lt;<span class="keyword">typename</span> ScannerT, <span class="keyword">typename</span> ErrorT&gt;
     boost::spirit::error_status&lt;&gt; operator()(ScannerT, ErrorT)<span class="keyword"> const</span>
<span class="keyword">     </span>{
     ...
     }
 };
</pre></div><p>
<code><a class="el" href="structopenvrml_1_1vrml97__grammar.html" title="A Spirit grammar for parsing VRML97.">openvrml::vrml97_grammar</a></code> defaults to using <code><a class="el" href="structopenvrml_1_1vrml97__parse__error__handler.html" title="A Spirit error handler that emits error and warning messages to a std::ostream.">openvrml::vrml97_parse_error_handler</a></code>; and <code><a class="el" href="structopenvrml_1_1x3d__vrml__grammar.html" title="A Spirit grammar for parsing Classic VRML X3D.">openvrml::x3d_vrml_grammar</a></code> defaults to using <code><a class="el" href="structopenvrml_1_1x3d__vrml__parse__error__handler.html" title="A Spirit error handler that emits error and warning messages to a std::ostream.">openvrml::x3d_vrml_parse_error_handler</a></code>. For most common cases, these types will be quite sufficient. Their constructors take an <code>std::ostream</code>; so, to emit output somewhere other than <code>stderr</code>, one need only construct an instance of one of these error handlers with the desired <code>std::ostream</code> and pass that to the grammar capsule constructor.<h2><a class="anchor" name="further_information_on_spirit">
2.6 Further information</a></h2>
The objective of this portion of OpenVRML's manual has been to provide a high-level view of parsing with the provided Spirit grammars. There is a great deal of depth and flexibility built into the Spirit framework; and while exploring that is beyond the scope of this manual, the <a href="http://spirit.sourceforge.net/documentation.html">Spirit User's Guide</a> is an excellent resource. </div>
</div>
<address class="footer"><span class="images"><a href="http://web3d.org/x3d/"><img src="x3d-white-on-black.png" width="43" height="32" border="0" alt="X3D"></a><a href="http://opengl.org"><img src="OGL_sm_wht.png" width="68" height="32" border="0" alt="OpenGL"></a><a href="http://sourceforge.net/projects/openvrml"><img src="http://sourceforge.net/sflogo.php?group_id=7151&amp;type=11" width="120" height="30" border="0" alt="SourceForge.net"></a></span><a href="https://sourceforge.net/apps/trac/openvrml/newticket">Report error</a><br>Generated Thu Aug 13 02:49:12 2009 by Doxygen 1.5.8</address>
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
<script type="text/javascript">_uacct = "UA-446379-2"; urchinTracker();</script>
<!-- Piwik -->
<script type="text/javascript">
var pkBaseURL = (("https:" == document.location.protocol) ? "https://sourceforge.net/apps/piwik/openvrml/" : "http://sourceforge.net/apps/piwik/openvrml/");
document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
</script><script type="text/javascript">
piwik_action_name = '';
piwik_idsite = 1;
piwik_url = pkBaseURL + "piwik.php";
piwik_log(piwik_action_name, piwik_idsite, piwik_url);
</script>
<object><noscript><p><img src="http://sourceforge.net/apps/piwik/openvrml/piwik.php?idsite=1" alt="piwik"/></p></noscript></object>
<!-- End Piwik Tag -->
</body>
</html>