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

Revision 11290, 24.1 kB (checked in by robert, 4 years ago)

From Mathias Froehlich, "I added some features to the vrml plugin.

The plugin can now handle embeded PixelTexture? fields in addition to the
already implemented ImageTexture? fields.

Fixed a bug with texture repeat being applied to the wrong texture dimension.

Added handling for IndexedLineSet? geometries."

  • 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()=="IndexedLineSet")
319                    osg_geom = convertVRML97IndexedLineSet(node_ptr.get());
320
321                else if (node_ptr->type().id() == "Box")
322                    osg_geom = convertVRML97Box(node_ptr.get());
323
324                else if (node_ptr->type().id() == "Sphere")
325                    osg_geom = convertVRML97Sphere(node_ptr.get());
326
327                else if (node_ptr->type().id() == "Cone")
328                    osg_geom = convertVRML97Cone(node_ptr.get());
329
330                else if (node_ptr->type().id() == "Cylinder")
331                    osg_geom = convertVRML97Cylinder(node_ptr.get());
332
333                else
334                {
335                    // other geometry types not handled yet
336                }
337            }
338        }
339
340        osg::ref_ptr<osg::Geode> osg_geode = new osg::Geode();
341        osg_geode->addDrawable(osg_geom.get());
342        osg::StateSet *osg_stateset = osg_geode->getOrCreateStateSet();
343
344        osg::ref_ptr<osg::Material> osg_mat = new osg::Material();
345        osg_stateset->setAttributeAndModes(osg_mat.get());
346        osg_mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
347
348        // parse the appearance
349        {
350            std::auto_ptr<openvrml::field_value> fv = obj->field("appearance");
351
352            if (fv->type() == openvrml::field_value::sfnode_id)
353            {
354                const openvrml::sfnode *sfn = dynamic_cast<const openvrml::sfnode *>(fv.get());
355                openvrml::appearance_node *vrml_app = dynamic_cast<openvrml::appearance_node *>(sfn->value().get());
356
357                const boost::intrusive_ptr<openvrml::node> vrml_material_node = vrml_app->material();
358                const boost::intrusive_ptr<openvrml::texture_node> vrml_texture_node = openvrml::node_cast<openvrml::texture_node*>(vrml_app->texture().get());
359                const openvrml::material_node *vrml_material = dynamic_cast<const openvrml::material_node *>(vrml_material_node.get());
360
361                if (vrml_material != NULL)
362                {
363                    osg_mat->setAmbient(osg::Material::FRONT_AND_BACK,
364                                    osg::Vec4(vrml_material->ambient_intensity(),
365                                                    vrml_material->ambient_intensity(),
366                                                    vrml_material->ambient_intensity(),
367                                                    1.0));
368                    osg_mat->setDiffuse(osg::Material::FRONT_AND_BACK,
369                                    osg::Vec4(vrml_material->diffuse_color().r(),
370                                                    vrml_material->diffuse_color().g(),
371                                                    vrml_material->diffuse_color().b(),
372                                                    1.0));
373                    osg_mat->setEmission(osg::Material::FRONT_AND_BACK,
374                                    osg::Vec4(vrml_material->emissive_color().r(),
375                                                    vrml_material->emissive_color().g(),
376                                                    vrml_material->emissive_color().b(),
377                                                    1.0));
378                    osg_mat->setSpecular(osg::Material::FRONT_AND_BACK,
379                                    osg::Vec4(vrml_material->specular_color().r(),
380                                                    vrml_material->specular_color().g(),
381                                                    vrml_material->specular_color().b(),
382                                                    1.0));
383
384                    osg_mat->setShininess(osg::Material::FRONT_AND_BACK, vrml_material->shininess() );
385
386                    if (vrml_material->transparency() > 0.0f)
387                    {
388                        osg_mat->setTransparency(osg::Material::FRONT_AND_BACK, vrml_material->transparency());
389                        osg_stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
390                        osg_stateset->setAttribute(new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false)); // GvdB: transparent objects do not write depth
391                        osg_stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
392                    }
393                    else
394                    {
395                        osg_stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
396                        osg_stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN);
397                    }
398
399                    osg_stateset->setAttributeAndModes(osg_mat.get());
400
401                }
402
403                // if texture is provided
404                if (vrml_texture_node != 0)
405                {
406                    osg::ref_ptr<osg::Image> image;
407
408                    if (vrml_texture_node->type().id() == "ImageTexture")
409                    {
410                        try
411                        {
412                            std::auto_ptr<openvrml::field_value> texture_url_fv = vrml_texture_node->field("url");
413                            const openvrml::mfstring *mfs = dynamic_cast<const openvrml::mfstring *>(texture_url_fv.get());
414                            const std::string &url = mfs->value()[0];
415                           
416                            image = osgDB::readRefImageFile(url);
417                           
418                            if (!image.valid())
419                            {
420                                std::cerr << "texture file " << url << " not found !" << std::endl << std::flush;
421                            }
422                        }
423                        catch (openvrml::unsupported_interface&)
424                        {
425                            // no url field in the texture
426                        }
427                    }
428
429                    if (!image.valid())
430                    {
431                        // If we cannot read the image try the openvrml builtin mechanisms to read the image.
432                        // This includes PixelTexture fields.
433                        const openvrml::image& vrml_image = vrml_texture_node->image();
434
435                        // Convert to an osg image
436                        image = new osg::Image;
437                        image->allocateImage(vrml_image.x(), vrml_image.y(), 1, GL_RGBA, GL_UNSIGNED_BYTE);
438                        for (std::size_t y = 0; y < vrml_image.y(); ++y)
439                        {
440                            for (std::size_t x = 0; x < vrml_image.x(); ++x)
441                            {
442                                openvrml::int32 p = vrml_image.pixel(x, y);
443                                unsigned char* data = image->data(x, y);
444                                data[0] = 0xff & (p >> 24);
445                                data[1] = 0xff & (p >> 16);
446                                data[2] = 0xff & (p >> 8);
447                                data[3] = 0xff & (p >> 0);
448                            }
449                        }
450                    }
451
452                    if (image.valid())
453                    {
454                        osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
455                        texture->setImage(image.get());
456
457                        // get the real texture wrapping parameters
458                        if (vrml_texture_node->repeat_s())
459                        {
460                            texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
461                        }
462                        else
463                        {
464                            texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
465                        }
466
467                        if (vrml_texture_node->repeat_t())
468                        {
469                            texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
470                        }
471                        else
472                        {
473                            texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
474                        }
475                        texture->setWrap(osg::Texture::WRAP_R, osg::Texture::REPEAT);
476
477                        osg_stateset->setTextureAttributeAndModes(0, texture.get());
478
479                        if (image->isImageTranslucent()) {
480                            osg_stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
481                            osg_stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
482                        }
483                    }
484                }
485            }
486        }
487
488        return osg_geode.get();
489    }
490    else
491    {
492        return 0;
493    }
494#if 0
495    /*
496     } else if(obj->type.id == "DirectionalLight")    // Handle lights
497     {
498     osg::Group* lightGroup = new osg::Group;
499
500     openvrml::vrml97_node::directional_light_node *vrml_light;
501     vrml_light = dynamic_cast<openvrml::vrml97_node::directional_light_node *>(obj);
502
503     // create light with global params
504     osg::Light* myLight = new osg::Light;
505     myLight->setLightNum(osgLightNum);
506     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
507     float osgR = vrml_light->color().r()*vrml_light->intensity();
508     float osgG = vrml_light->color().g()*vrml_light->intensity();
509     float osgB = vrml_light->color().b()*vrml_light->intensity();
510     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
511     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
512
513     // configure light as DIRECTIONAL
514     openvrml::sfvec3f &dir = vrml_light->direction_;
515     myLight->setDirection(osg::Vec3(dir.value[0],dir.value[1],dir.value[2]));
516     myLight->setPosition(osg::Vec4(dir.value[0],dir.value[1],dir.value[2], 0.0f));
517
518     // add the light in the scenegraph
519     osg::LightSource* lightS = new osg::LightSource;
520     lightS->setLight(myLight);
521     if (vrml_light->on()) {
522     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
523     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
524     }
525
526     lightGroup->addChild(lightS);
527     osgLightNum++;
528
529     return lightGroup;
530
531     } else if(obj->type.id == "PointLight")    // Handle lights
532     {
533     osg::Group* lightGroup = new osg::Group;
534
535     openvrml::vrml97_node::point_light_node *vrml_light;
536     vrml_light = dynamic_cast<openvrml::vrml97_node::point_light_node *>(obj);
537
538     // create light with global params
539     osg::Light* myLight = new osg::Light;
540     myLight->setLightNum(osgLightNum);
541     //std::cout<<"lightnum = "<<osgLightNum;
542
543     openvrml::sfvec3f &pos = vrml_light->location_;
544     myLight->setPosition(osg::Vec4(pos.value[0], pos.value[1], pos.value[2], 1.0f));
545
546     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
547     float osgR = vrml_light->color().r()*vrml_light->intensity();
548     float osgG = vrml_light->color().g()*vrml_light->intensity();
549     float osgB = vrml_light->color().b()*vrml_light->intensity();
550     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
551     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
552
553     // configure light as POINT
554     myLight->setDirection(osg::Vec3(0.f,0.f,0.f));
555
556     // add the light in the scenegraph
557     osg::LightSource* lightS = new osg::LightSource;
558     lightS->setLight(myLight);
559     if (vrml_light->on()) {
560     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
561     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
562     }
563
564     lightGroup->addChild(lightS);
565     osgLightNum++;
566
567     return lightGroup;
568
569     } else if(obj->type.id == "SpotLight")    // Handle lights
570     {
571     osg::Group* lightGroup = new osg::Group;
572
573     openvrml::vrml97_node::spot_light_node *vrml_light;
574     vrml_light = dynamic_cast<openvrml::vrml97_node::spot_light_node *>(obj);
575
576     // create light with global params
577     osg::Light* myLight = new osg::Light;
578     myLight->setLightNum(osgLightNum);
579     myLight->setPosition(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
580     myLight->setAmbient(osg::Vec4(vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity(),vrml_light->ambient_intensity()));
581     float osgR = vrml_light->color().r()*vrml_light->intensity();
582     float osgG = vrml_light->color().g()*vrml_light->intensity();
583     float osgB = vrml_light->color().b()*vrml_light->intensity();
584     myLight->setDiffuse(osg::Vec4(osgR, osgG, osgB, 1.0f));
585     myLight->setSpecular(osg::Vec4(osgR, osgG, osgB, 1.0f));
586
587     // configure light as SPOT
588     openvrml::sfvec3f &dir = vrml_light->direction_;
589     myLight->setDirection(osg::Vec3(dir.value[0],dir.value[1],dir.value[2]));
590
591     // The cutOff value in osg ranges from 0 to 90, we need
592     // to divide by 2 to avoid openGL error.
593     //      myLight->setSpotCutoff(ls.fallsize/2.0f);
594     // The bigger the differens is between fallsize and hotsize
595     // the bigger the exponent should be.
596     //      float diff = ls.fallsize - ls.hotsize;
597     //      myLight->setSpotExponent(diff);
598
599     // add the light in the scenegraph
600     osg::LightSource* lightS = new osg::LightSource;
601     lightS->setLight(myLight);
602     if (vrml_light->on()) {
603     lightS->setLocalStateSetModes(osg::StateAttribute::ON);
604     //lightS->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
605     }
606
607     lightGroup->addChild(lightS);
608     osgLightNum++;
609
610     return lightGroup;
611
612     }  else {
613
614     return NULL;
615     }
616     */
617
618#endif
619
620    return 0;
621}
Note: See TracBrowser for help on using the browser.