root/OpenSceneGraph/trunk/src/osgPlugins/vrml/ReaderWriterVRML2.cpp @ 10785

Revision 10785, 22.7 kB (checked in by robert, 4 years ago)

From Jan Ciger, build fixes to work with OpenVRML 0.18.3.

Tweaks to this submission from Robert Osfield to fix missing elements in submission.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// -*-c++-*-
2
3/*
4 *
5 * VRML2 file converter for OpenSceneGraph.
6 *
7 * authors : Jan Ciger (jan.ciger@gmail.com),
8 *           Tolga Abaci (tolga.abaci@gmail.com),
9 *           Bruno Herbelin (bruno.herbelin@gmail.com)
10 *
11 *           (c) VRlab EPFL, Switzerland, 2004-2006
12 *
13 *           Gino van den Bergen, DTECTA (gino@dtecta.com)
14 *           Xiangxian Wang (xiangxianwang@yahoo.com.cn)
15 *
16 */
17
18#include "ReaderWriterVRML2.h"
19
20#include <iostream>
21#include <fstream>
22
23#include <boost/algorithm/string/predicate.hpp>
24#include <boost/utility.hpp>
25
26#if defined(_MSC_VER)
27#   pragma warning(disable: 4250)
28#   pragma warning(disable: 4290)
29#   pragma warning(disable: 4800)
30#endif
31
32#include <openvrml/browser.h>
33#include <openvrml/node.h>
34
35#include <osg/TexEnv>
36#include <osg/CullFace>
37
38#include <osg/Geode>
39#include <osg/Geometry>
40#include <osg/Material>
41#include <osg/Image>
42#include <osg/Texture2D>
43#include <osg/Group>
44#include <osg/MatrixTransform>
45#include <osg/Light>
46#include <osg/LightSource>
47#include <osg/Depth>
48
49#include <osg/Notify>
50#include <osgDB/Registry>
51#include <osgDB/ReadFile>
52#include <osgDB/FileNameUtils>
53#include <osgDB/FileUtils>
54
55#include <assert.h>
56#include <map>
57
58// -------------------------------------------------------------------------------------
59// OpenVRML helper class
60// -------------------------------------------------------------------------------------
61class resource_fetcher: public openvrml::resource_fetcher
62{
63    private:
64        virtual std::auto_ptr<openvrml::resource_istream> do_get_resource(const std::string & uri)
65        {
66            using std::auto_ptr;
67            using std::invalid_argument;
68            using std::string;
69            using openvrml::resource_istream;
70
71            class file_resource_istream: public resource_istream
72            {
73                    std::string url_;
74                    std::filebuf buf_;
75
76                public:
77                    explicit file_resource_istream(const std::string & path) :
78                        resource_istream(&this->buf_)
79                    {
80                        //
81                        // Note that the failbit is set in the constructor if no data
82                        // can be read from the stream.  This is important.  If the
83                        // failbit is not set on such a stream, OpenVRML will attempt
84                        // to read data from a stream that cannot provide it.
85                        //
86                        if (!this->buf_.open(path.c_str(), ios_base::in | ios_base::binary))
87                        {
88                            this->setstate(ios_base::badbit);
89                        }
90                    }
91
92                    void url(const std::string & str) throw (std::bad_alloc)
93                    {
94                        this->url_ = str;
95                    }
96
97                private:
98                    virtual const std::string do_url() const throw ()
99                    {
100                        return this->url_;
101                    }
102
103                    virtual const std::string do_type() const throw ()
104                    {
105                        //
106                        // A real application should use OS facilities for this;
107                        // however, that is beyond the scope of this example (which
108                        // is intended to be portable and stupid).
109                        //
110                        using std::find;
111                        using std::string;
112                        using boost::algorithm::iequals;
113                        using boost::next;
114                        string media_type = "application/octet-stream";
115
116                        const string::const_reverse_iterator dot_pos = find(this->url_.rbegin(), this->url_.rend(), '.');
117                        if (dot_pos == this->url_.rend() || next(dot_pos.base()) == this->url_.end())
118                        {
119                            return media_type;
120                        }
121
122                        const string::const_iterator hash_pos = find(next(dot_pos.base()), this->url_.end(), '#');
123                        const string ext(dot_pos.base(), hash_pos);
124
125                        if (iequals(ext, "wrl") || iequals(ext, "vrml"))
126                        {
127                            media_type = "model/vrml";
128                        }
129                        else if (iequals(ext, "png"))
130                        {
131                            media_type = "image/png";
132                        }
133                        else if (iequals(ext, "jpg") || iequals(ext, "jpeg"))
134                        {
135                            media_type = "image/jpeg";
136                        }
137                        return media_type;
138                    }
139
140                    virtual bool do_data_available() const throw ()
141                    {
142                        return !!(*this);
143                    }
144            };
145
146            const string scheme = uri.substr(0, uri.find_first_of(':'));
147            if (scheme != "file")
148            {
149                throw invalid_argument('\"' + scheme + "\" URI scheme not "
150                    "supported");
151            }
152            //
153            // file://
154            //        ^
155            // 01234567
156            //
157            string path = uri.substr(uri.find_first_of('/', 7));
158
159            auto_ptr<resource_istream> in(new file_resource_istream(path));
160            static_cast<file_resource_istream *> (in.get())->url(uri);
161
162            return in;
163        }
164};
165
166// -------------------------------------------------------------------------------------
167
168
169// Register with Registry to instantiate the above reader/writer.
170REGISTER_OSGPLUGIN(vrml, ReaderWriterVRML2)
171
172osgDB::ReaderWriter::ReadResult ReaderWriterVRML2::readNode(const std::string& fname, const osgDB::Options* opt) const
173{
174    std::string fileName = osgDB::findDataFile(fname, opt);
175    if (fileName.empty())
176        return ReadResult::FILE_NOT_FOUND;
177
178    // convert possible Windows backslashes to Unix slashes
179    // OpenVRML doesn't like backslashes, even on Windows
180    std::string unixFileName = osgDB::convertFileNameToUnixStyle(fileName);
181
182#ifdef WIN32
183    if(unixFileName[1] == ':') // absolute path
184    fileName = "file:///" + unixFileName;
185#else
186    if (unixFileName[0] == '/') // absolute path
187        fileName = "file://" + unixFileName;
188#endif
189    else
190        // relative path
191        fileName = unixFileName;
192
193    std::fstream null;
194    resource_fetcher fetcher;
195    openvrml::browser *b = new openvrml::browser(fetcher, null, null);
196
197    std::ifstream vrml_stream(fileName.c_str());
198
199    try
200    {
201        const std::vector< boost::intrusive_ptr< openvrml::node > > & mfn = b->create_vrml_from_stream(vrml_stream);
202
203        if(mfn.empty())
204            return ReadResult::FILE_NOT_HANDLED;
205        else
206        {
207            osg::ref_ptr<osg::MatrixTransform> osg_root = new osg::MatrixTransform(osg::Matrix( 1, 0, 0, 0,
208                                                                                                0, 0, 1, 0,
209                                                                                                0, -1, 0, 0,
210                                                                                                0, 0, 0, 1));
211
212            osgDB::getDataFilePathList().push_front(osgDB::getFilePath(unixFileName));
213            for (unsigned i = 0; i < mfn.size(); i++)
214            {
215                openvrml::node *vrml_node = mfn[i].get();
216                osg_root->addChild(convertFromVRML(vrml_node).get());
217            }
218            osgDB::getDataFilePathList().pop_front();
219            return osg_root.get();
220        }
221    }
222
223    catch (openvrml::invalid_vrml) { return ReadResult::FILE_NOT_HANDLED; }
224    catch (std::invalid_argument)  { return ReadResult::FILE_NOT_HANDLED; }
225}
226
227osg::ref_ptr<osg::Node> ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) const
228{
229    //static int osgLightNum = 0; //light
230
231    if (obj->type().id() == "Group") // Group node
232
233    {
234        openvrml::grouping_node *vrml_group;
235        vrml_group = dynamic_cast<openvrml::grouping_node *>(obj);
236
237        osg::ref_ptr<osg::Group> osg_group = new osg::Group;
238
239        try
240        {
241            std::auto_ptr<openvrml::field_value> fv = obj->field("children");
242
243            if ( fv->type() == openvrml::field_value::mfnode_id )
244            {
245                const openvrml::mfnode* mfn = dynamic_cast<const openvrml::mfnode *>(fv.get());
246                openvrml::mfnode::value_type node_ptr_vector = mfn->value();
247                openvrml::mfnode::value_type::iterator it_npv;
248
249                for (it_npv = node_ptr_vector.begin(); it_npv != node_ptr_vector.end(); it_npv++)
250                {
251                    openvrml::node *node = (*(it_npv)).get();
252                    osg_group->addChild(convertFromVRML(node));
253                }
254            }
255        }
256        catch (openvrml::unsupported_interface&)
257        {
258            // no children
259        }
260
261        return osg_group.get();
262
263    }
264
265    else if (obj->type().id() == "Transform") // Handle transforms
266
267    {
268        openvrml::transform_node *vrml_transform;
269        vrml_transform = dynamic_cast<openvrml::transform_node *>(obj);
270
271        openvrml::mat4f vrml_m = vrml_transform->transform();
272        osg::ref_ptr<osg::MatrixTransform> osg_m = new osg::MatrixTransform(osg::Matrix(vrml_m[0][0], vrml_m[0][1], vrml_m[0][2], vrml_m[0][3], vrml_m[1][0], vrml_m[1][1], vrml_m[1][2], vrml_m[1][3], vrml_m[2][0], vrml_m[2][1], vrml_m[2][2], vrml_m[2][3], vrml_m[3][0], vrml_m[3][1], vrml_m[3][2], vrml_m[3][3]));
273
274        try
275        {
276            std::auto_ptr<openvrml::field_value> fv = obj->field("children");
277
278            if ( fv->type() == openvrml::field_value::mfnode_id )
279            {
280                const openvrml::mfnode* mfn = dynamic_cast<const openvrml::mfnode *>(fv.get());
281                openvrml::mfnode::value_type node_ptr_vector = mfn->value();
282                openvrml::mfnode::value_type::iterator it_npv;
283
284                for (it_npv = node_ptr_vector.begin(); it_npv != node_ptr_vector.end(); it_npv++)
285                {
286                    openvrml::node *node = (*(it_npv)).get();
287                    osg_m->addChild(convertFromVRML(node).get());
288                }
289            }
290        }
291        catch (openvrml::unsupported_interface&)
292        {
293            // no children
294        }
295
296        return osg_m.get();
297
298    }
299
300    else if ((obj->type()).id() == "Shape") // Handle Shape node
301
302    {
303        osg::ref_ptr<osg::Geometry> osg_geom;
304
305        // parse the geometry
306        {
307            std::auto_ptr<openvrml::field_value> fv = obj->field("geometry");
308
309            if (fv->type() == openvrml::field_value::sfnode_id)
310            {
311                const openvrml::sfnode * sfn = dynamic_cast<const openvrml::sfnode *>(fv.get());
312                openvrml::sfnode::value_type node_ptr = sfn->value();
313
314                // is it indexed_face_set_node ?
315                if (node_ptr->type().id()=="IndexedFaceSet")
316                    osg_geom = convertVRML97IndexedFaceSet(node_ptr.get());
317
318                else if (node_ptr->type().id() == "Box")
319                    osg_geom = convertVRML97Box(node_ptr.get());
320
321                else if (node_ptr->type().id() == "Sphere")
322                    osg_geom = convertVRML97Sphere(node_ptr.get());
323
324                else if (node_ptr->type().id() == "Cone")
325                    osg_geom = convertVRML97Cone(node_ptr.get());
326
327                else if (node_ptr->type().id() == "Cylinder")
328                    osg_geom = convertVRML97Cylinder(node_ptr.get());
329
330                else
331                {
332                    // other geometry types not handled yet
333                }
334            }
335        }
336
337        osg::ref_ptr<osg::Geode> osg_geode = new osg::Geode();
338        osg_geode->addDrawable(osg_geom.get());
339        osg::StateSet *osg_stateset = osg_geode->getOrCreateStateSet();
340
341        osg::ref_ptr<osg::Material> osg_mat = new osg::Material();
342        osg_stateset->setAttributeAndModes(osg_mat.get());
343        osg_mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
344
345        // parse the appearance
346        {
347            std::auto_ptr<openvrml::field_value> fv = obj->field("appearance");
348
349            if (fv->type() == openvrml::field_value::sfnode_id)
350            {
351                const openvrml::sfnode *sfn = dynamic_cast<const openvrml::sfnode *>(fv.get());
352                openvrml::appearance_node *vrml_app = dynamic_cast<openvrml::appearance_node *>(sfn->value().get());
353
354                const boost::intrusive_ptr<openvrml::node> vrml_material_node = vrml_app->material();
355                const boost::intrusive_ptr<openvrml::node> vrml_texture_node = vrml_app->texture();
356                const openvrml::material_node *vrml_material = dynamic_cast<const openvrml::material_node *>(vrml_material_node.get());
357
358                if (vrml_material != NULL)
359                {
360                    osg_mat->setAmbient(osg::Material::FRONT_AND_BACK,
361                                    osg::Vec4(vrml_material->ambient_intensity(),
362                                                    vrml_material->ambient_intensity(),
363                                                    vrml_material->ambient_intensity(),
364                                                    1.0));
365                    osg_mat->setDiffuse(osg::Material::FRONT_AND_BACK,
366                                    osg::Vec4(vrml_material->diffuse_color().r(),
367                                                    vrml_material->diffuse_color().g(),
368                                                    vrml_material->diffuse_color().b(),
369                                                    1.0));
370                    osg_mat->setEmission(osg::Material::FRONT_AND_BACK,
371                                    osg::Vec4(vrml_material->emissive_color().r(),
372                                                    vrml_material->emissive_color().g(),
373                                                    vrml_material->emissive_color().b(),
374                                                    1.0));
375                    osg_mat->setSpecular(osg::Material::FRONT_AND_BACK,
376                                    osg::Vec4(vrml_material->specular_color().r(),
377                                                    vrml_material->specular_color().g(),
378                                                    vrml_material->specular_color().b(),
379                                                    1.0));
380
381                    osg_mat->setShininess(osg::Material::FRONT_AND_BACK, vrml_material->shininess() );
382
383                    if (vrml_material->transparency() > 0.0f)
384                    {
385                        osg_mat->setTransparency(osg::Material::FRONT_AND_BACK, vrml_material->transparency());
386                        osg_stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
387                        osg_stateset->setAttribute(new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false)); // GvdB: transparent objects do not write depth
388                        osg_stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
389                    }
390                    else
391                    {
392                        osg_stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
393                        osg_stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN);
394                    }
395
396                    osg_stateset->setAttributeAndModes(osg_mat.get());
397
398                }
399
400                // if texture is provided
401                if (vrml_texture_node != 0)
402                {
403                    std::auto_ptr<openvrml::field_value> texture_url_fv = vrml_texture_node->field("url");
404                    const openvrml::mfstring *mfs = dynamic_cast<const openvrml::mfstring *>(texture_url_fv.get());
405                    const std::string &url = mfs->value()[0];
406
407                    osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(url);
408
409                    if (image != 0)
410                    {
411                        osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
412                        texture->setImage(image.get());
413
414                        // defaults
415                        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
416                        texture->setWrap(osg::Texture::WRAP_R, osg::Texture::REPEAT);
417                        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
418
419                        // get the real texture wrapping parameters (if any)
420                        try
421                        {
422                            std::auto_ptr<openvrml::field_value> wrap_fv = vrml_texture_node->field("repeatS");
423                            const openvrml::sfbool *sfb = dynamic_cast<const openvrml::sfbool *>(wrap_fv.get());
424
425                            if (!sfb->value())
426                                texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
427
428                        }
429                        catch (...)
430                        {
431                            // nothing specified
432                        }
433
434                        try
435                        {
436                            std::auto_ptr<openvrml::field_value> wrap_fv = vrml_texture_node->field("repeatT");
437                            const openvrml::sfbool *sfb = dynamic_cast<const openvrml::sfbool *>(wrap_fv.get());
438
439                            if (!sfb->value())
440                                texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
441                        }
442                        catch (...)
443                        {
444                            // nothing specified
445                        }
446
447                        osg_stateset->setTextureAttributeAndModes(0, texture.get());
448                        //osg_stateset->setMode(GL_BLEND,osg::StateAttribute::ON);  //bhbn
449
450                    }
451                    else
452                    {
453                        std::cerr << "texture file " << url << " not found !" << std::endl << std::flush;
454                    }
455                }
456            }
457        }
458
459        return osg_geode.get();
460    }
461    else
462    {
463        return 0;
464    }
465#if 0
466    /*
467     } else if(obj->type.id == "DirectionalLight")    // Handle lights
468     {
469     osg::Group* lightGroup = new osg::Group;
470
471     openvrml::vrml97_node::directional_light_node *vrml_light;
472     vrml_light = dynamic_cast<openvrml::vrml97_node::directional_light_node *>(obj);
473
474     // create light with global params
475     osg::Light* myLight = new osg::Light;
476     myLight->setLightNum(osgLightNum);
477     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
478     float osgR = vrml_light->color().r()*vrml_light->intensity();
479     float osgG = vrml_light->color().g()*vrml_light->intensity();
480     float osgB = vrml_light->color().b()*vrml_light->intensity();
481     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
482     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
483
484     // configure light as DIRECTIONAL
485     openvrml::sfvec3f &dir = vrml_light->direction_;
486     myLight->setDirection(osg::Vec3(dir.value[0],dir.value[1],dir.value[2]));
487     myLight->setPosition(osg::Vec4(dir.value[0],dir.value[1],dir.value[2], 0.0f));
488
489     // add the light in the scenegraph
490     osg::LightSource* lightS = new osg::LightSource;
491     lightS->setLight(myLight);
492     if (vrml_light->on()) {
493     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
494     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
495     }
496
497     lightGroup->addChild(lightS);
498     osgLightNum++;
499
500     return lightGroup;
501
502     } else if(obj->type.id == "PointLight")    // Handle lights
503     {
504     osg::Group* lightGroup = new osg::Group;
505
506     openvrml::vrml97_node::point_light_node *vrml_light;
507     vrml_light = dynamic_cast<openvrml::vrml97_node::point_light_node *>(obj);
508
509     // create light with global params
510     osg::Light* myLight = new osg::Light;
511     myLight->setLightNum(osgLightNum);
512     //std::cout<<"lightnum = "<<osgLightNum;
513
514     openvrml::sfvec3f &pos = vrml_light->location_;
515     myLight->setPosition(osg::Vec4(pos.value[0], pos.value[1], pos.value[2], 1.0f));
516
517     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
518     float osgR = vrml_light->color().r()*vrml_light->intensity();
519     float osgG = vrml_light->color().g()*vrml_light->intensity();
520     float osgB = vrml_light->color().b()*vrml_light->intensity();
521     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
522     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
523
524     // configure light as POINT
525     myLight->setDirection(osg::Vec3(0.f,0.f,0.f));
526
527     // add the light in the scenegraph
528     osg::LightSource* lightS = new osg::LightSource;
529     lightS->setLight(myLight);
530     if (vrml_light->on()) {
531     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
532     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
533     }
534
535     lightGroup->addChild(lightS);
536     osgLightNum++;
537
538     return lightGroup;
539
540     } else if(obj->type.id == "SpotLight")    // Handle lights
541     {
542     osg::Group* lightGroup = new osg::Group;
543
544     openvrml::vrml97_node::spot_light_node *vrml_light;
545     vrml_light = dynamic_cast<openvrml::vrml97_node::spot_light_node *>(obj);
546
547     // create light with global params
548     osg::Light* myLight = new osg::Light;
549     myLight->setLightNum(osgLightNum);
550     myLight->setPosition(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
551     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
552     float osgR = vrml_light->color().r()*vrml_light->intensity();
553     float osgG = vrml_light->color().g()*vrml_light->intensity();
554     float osgB = vrml_light->color().b()*vrml_light->intensity();
555     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
556     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
557
558     // configure light as SPOT
559     openvrml::sfvec3f &dir = vrml_light->direction_;
560     myLight->setDirection(osg::Vec3(dir.value[0],dir.value[1],dir.value[2]));
561
562     // The cutOff value in osg ranges from 0 to 90, we need
563     // to divide by 2 to avoid openGL error.
564     //      myLight->setSpotCutoff(ls.fallsize/2.0f);
565     // The bigger the differens is between fallsize and hotsize
566     // the bigger the exponent should be.
567     //      float diff = ls.fallsize - ls.hotsize;
568     //      myLight->setSpotExponent(diff);
569
570     // add the light in the scenegraph
571     osg::LightSource* lightS = new osg::LightSource;
572     lightS->setLight(myLight);
573     if (vrml_light->on()) {
574     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
575     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
576     }
577
578     lightGroup->addChild(lightS);
579     osgLightNum++;
580
581     return lightGroup;
582
583     }  else {
584
585     return NULL;
586     }
587     */
588
589#endif
590
591    return 0;
592}
Note: See TracBrowser for help on using the browser.