GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/leaf-node-collada.cpp Lines: 3 206 1.5 %
Date: 2020-05-14 11:23:33 Branches: 2 388 0.5 %

Line Branch Exec Source
1
//
2
//  leaf-node-collada.cpp
3
//  gepetto-viewer
4
//
5
//  Created by Anthony Couret, Mathieu Geisert in November 2014.
6
//  Copyright (c) 2014 LAAS-CNRS. All rights reserved.
7
//
8
9
#include <sys/stat.h>
10
#include <fstream>
11
#include <clocale>
12
#include <ios>
13
#include <osg/LightModel>
14
#include <osg/Texture2D>
15
#include <osg/Version>
16
#include <osgDB/FileNameUtils>
17
#include <gepetto/viewer/leaf-node-collada.h>
18
19
namespace gepetto {
20
namespace viewer {
21
  inline bool fileExists (const char* fn)
22
  { struct stat buffer; return (stat (fn, &buffer) == 0); }
23
24
  std::string getCachedFileName (const std::string& meshfile)
25
  {
26
    static const std::string exts[3] = { ".osgb", ".osg2", ".osg" };
27
    for (int i = 0; i < 3; ++i) {
28
      std::string cached = meshfile + exts[i];
29
      if (fileExists(cached.c_str())) return cached;
30
    }
31
    return std::string();
32
  }
33
34
  bool getBackfaceDrawing (LeafNodeCollada* node) {
35
    return (bool)(node->getColladaPtr()->getOrCreateStateSet()
36
        ->getMode(GL_CULL_FACE) & osg::StateAttribute::ON);
37
  }
38
  void setBackfaceDrawing (LeafNodeCollada* node, bool on) {
39
    osg::StateSet* ss = node->getColladaPtr()->getOrCreateStateSet();
40
41
    ss->setMode(GL_CULL_FACE,
42
          (on ?  osg::StateAttribute::ON : osg::StateAttribute::OFF));
43
44
    if (on) {
45
      osg::LightModel* ltModel = new osg::LightModel;
46
      ltModel->setTwoSided(on);
47
      ss->setAttribute(ltModel);
48
      ss->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
49
    } else {
50
      ss->removeAttribute(osg::StateAttribute::LIGHTMODEL);
51
      ss->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
52
    }
53
  }
54
55
  class LightSourceRemoving : public osg::NodeVisitor
56
  {
57
    public:
58
      LightSourceRemoving () : NodeVisitor (TRAVERSE_ALL_CHILDREN) {}
59
60
      void apply(osg::LightSource& node)
61
      {
62
        osg::Group* group = new osg::Group (node);
63
        for (unsigned int i = 0; i < node.getNumParents(); ++i)
64
          node.getParent(i)->replaceChild (&node, group);
65
      }
66
  };
67
68
#if OSG_VERSION_LESS_THAN(3,3,3)
69
2
  struct ObjectCache {
70
    typedef std::map<std::string, osg::NodeRefPtr> Map_t;
71
    Map_t map_;
72
    bool get (const std::string& name, osg::NodeRefPtr& node) const
73
    {
74
      Map_t::const_iterator it = map_.find (name);
75
      if (it != map_.end()) {
76
        node = it->second;
77
        return true;
78
      }
79
      return false;
80
    }
81
    void add (const std::string& name, osg::NodeRefPtr& node)
82
    {
83
      map_.insert (std::make_pair(name,node));
84
    }
85
    void erase (const std::string& name)
86
    {
87
      map_.erase(name);
88
    }
89
  };
90
91
1
  ObjectCache object_cache;
92
#else
93
  osg::ref_ptr<osgDB::ObjectCache> object_cache (new osgDB::ObjectCache);
94
#endif
95
96
  /* Declaration of private function members */
97
98
  void LeafNodeCollada::init()
99
  {
100
    group_ptr_ = new osg::Group;
101
    group_ptr_->setName ("groupForMaterial");
102
103
#if OSG_VERSION_LESS_THAN(3,3,3)
104
    if (!collada_ptr_)
105
      object_cache.get(collada_file_path_, collada_ptr_);
106
#endif
107
108
    if (!collada_ptr_) {
109
      // Setup cache
110
      const osg::ref_ptr<osgDB::Options> options = new osgDB::Options();
111
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
112
      options->setObjectCache (object_cache);
113
#endif
114
      options->setObjectCacheHint(osgDB::Options::CACHE_ALL);
115
116
      if (!fileExists(collada_file_path_.c_str()))
117
        throw std::invalid_argument(std::string("File ") + collada_file_path_ + std::string(" not found."));
118
119
      std::string osgname = getCachedFileName(collada_file_path_);
120
      if (!osgname.empty()) {
121
        std::cout << "Using " << osgname << std::endl;
122
        collada_ptr_ = osgDB::readNodeFile(osgname, options);
123
      } else {
124
        // get the extension of the meshs file
125
        std::string ext = osgDB::getLowerCaseFileExtension(collada_file_path_);
126
        if(ext == "obj"){
127
          options->setOptionString("noRotation");
128
          collada_ptr_ = osgDB::readNodeFile(collada_file_path_,options);
129
        }
130
        else if (ext == "dae") {
131
          float scale = 1.f;
132
          options->setPluginData("DAE-AssetUnitMeter", &scale);
133
          if (*localeconv()->decimal_point != '.') {
134
            std::cerr << "Warning: your locale convention uses '"
135
              << localeconv()->decimal_point << "' as decimal separator while DAE "
136
              "expects '.'.\nSet LC_NUMERIC to a locale convetion using '.' as "
137
              "decimal separator (e.g. export LC_NUMERIC=\"en_US.utf-8\")."
138
              << std::endl;
139
          }
140
141
          collada_ptr_ = osgDB::readNodeFile(collada_file_path_,options);
142
143
          // FIXME: Fixes https://github.com/Gepetto/gepetto-viewer/issues/95
144
          // The bug: Assimp seems to ignore the DAE up_axis tag. Because this
145
          // cannot be fixed in assimp without a huge impact, we make GV
146
          // compatible with assimp.
147
          //
148
          // The fix: OSG DAE plugin rotates the actual model with a root
149
          // PositionAttitudeTransform, when the DAE up axis is not Z.
150
          // We simply reset the attitude.
151
          osg::PositionAttitudeTransform* pat =
152
            dynamic_cast<osg::PositionAttitudeTransform*> (collada_ptr_.get());
153
          if (pat != NULL) {
154
            std::cout << "Reset up_axis to Z_UP." << std::endl;
155
            pat->setAttitude (osgQuat());
156
          }
157
158
          bool error = false;
159
          if (!collada_ptr_) {
160
            std::cout << "File: " << collada_file_path_ << " could not be loaded\n";
161
            error = true;
162
          } else if (strncasecmp(collada_ptr_->getName().c_str(), "empty", 5) == 0) {
163
            std::cout << "File: " << collada_file_path_ << " could not be loaded:\n"
164
              << collada_ptr_->getName() << '\n';
165
            error = true;
166
          }
167
          if (error) {
168
            std::cout << "You may try to convert the file with the following command:\n"
169
              "osgconv " << collada_file_path_ << ' ' << collada_file_path_ << ".osgb" << std::endl;
170
          }
171
          // Apply scale
172
          if (scale != 1.) {
173
            osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform;
174
            xform->setDataVariance( osg::Object::STATIC );
175
            xform->setMatrix( osg::Matrix::scale( scale, scale, scale ) );
176
            xform->addChild( collada_ptr_ );
177
            collada_ptr_ = xform;
178
          }
179
        } else
180
          collada_ptr_ = osgDB::readNodeFile(collada_file_path_,options);
181
      }
182
      if (!collada_ptr_)
183
        throw std::invalid_argument(std::string("File ") + collada_file_path_ + std::string(" found but could not be opened. Check that a plugin exist."));
184
#if OSG_VERSION_LESS_THAN(3,3,3)
185
      object_cache.add(collada_file_path_, collada_ptr_);
186
#endif
187
188
      /* Allow transparency */
189
      collada_ptr_->getOrCreateStateSet()->setMode(GL_BLEND, ::osg::StateAttribute::ON);
190
      collada_ptr_->setDataVariance(osg::Object::STATIC);
191
    }
192
    collada_ptr_->setName ("meshfile");
193
194
    /* Create PositionAttitudeTransform */
195
    group_ptr_->addChild(collada_ptr_);
196
    this->asQueue()->addChild(group_ptr_);
197
198
    addProperty(StringProperty::create("Mesh file",
199
          StringProperty::getterFromMemberFunction(this, &LeafNodeCollada::meshFilePath),
200
          StringProperty::Setter_t()));
201
    addProperty(BoolProperty::create("BackfaceDrawing",
202
          EnumProperty::Getter_t(boost::bind(getBackfaceDrawing, this)),
203
          EnumProperty::Setter_t(boost::bind(setBackfaceDrawing, this, _1))));
204
    addProperty(StringProperty::create("Texture file",
205
          StringProperty::getterFromMemberFunction(this, &LeafNodeCollada::textureFilePath),
206
          StringProperty::Setter_t()));
207
    addProperty(Vector4Property::create("Color",
208
          Vector4Property::getterFromMemberFunction(this, &LeafNodeCollada::getColor),
209
          Vector4Property::setterFromMemberFunction(this, &LeafNodeCollada::setColor)));
210
    addProperty(VoidProperty::create("RemoveLightSources",
211
          VoidProperty::memberFunction(this, &LeafNodeCollada::removeLightSources)));
212
  }
213
214
  LeafNodeCollada::LeafNodeCollada(const std::string& name, const std::string& collada_file_path) :
215
    Node(name), collada_file_path_(collada_file_path)
216
  {
217
    init();
218
  }
219
220
  LeafNodeCollada::LeafNodeCollada(const std::string& name, const std::string& collada_file_path, const osgVector4& color) :
221
    Node(name), collada_file_path_(collada_file_path)
222
  {
223
    init();
224
    setColor(color);
225
  }
226
227
  LeafNodeCollada::LeafNodeCollada(const std::string& name,
228
      const ::osg::NodeRefPtr& node, const std::string& collada_file_path) :
229
    Node(name), collada_file_path_(collada_file_path), collada_ptr_ (node)
230
  {
231
    init();
232
  }
233
234
  LeafNodeCollada::LeafNodeCollada(const LeafNodeCollada& other) :
235
    Node(other.getID()), collada_file_path_(other.collada_file_path_)
236
  {
237
    init();
238
  }
239
240
  void LeafNodeCollada::initWeakPtr(LeafNodeColladaWeakPtr other_weak_ptr)
241
  {
242
    weak_ptr_ = other_weak_ptr;
243
  }
244
245
  /* End of declaration of private function members */
246
247
  /* Declaration of protected function members */
248
249
  LeafNodeColladaPtr_t LeafNodeCollada::create(const std::string& name, const std::string& collada_file_path)
250
  {
251
    std::ifstream infile(collada_file_path.c_str ());
252
    if (!infile.good()) {
253
      throw std::ios_base::failure (collada_file_path +
254
                                    std::string (" does not exist."));
255
    }
256
    LeafNodeColladaPtr_t shared_ptr(new LeafNodeCollada
257
                                    (name, collada_file_path));
258
259
    // Add reference to itself
260
    shared_ptr->initWeakPtr(shared_ptr);
261
262
    return shared_ptr;
263
  }
264
265
  LeafNodeColladaPtr_t LeafNodeCollada::create(const std::string& name, ::osg::NodeRefPtr mesh, const std::string& collada_file_path)
266
  {
267
    LeafNodeColladaPtr_t shared_ptr(new LeafNodeCollada
268
                                    (name, mesh, collada_file_path));
269
270
    // Add reference to itself
271
    shared_ptr->initWeakPtr(shared_ptr);
272
273
    return shared_ptr;
274
  }
275
276
    LeafNodeColladaPtr_t LeafNodeCollada::create(const std::string& name, const std::string& collada_file_path, const osgVector4& color)
277
  {
278
    std::ifstream infile(collada_file_path.c_str ());
279
    if (!infile.good()) {
280
      throw std::ios_base::failure (collada_file_path +
281
                                    std::string (" does not exist."));
282
    }
283
    LeafNodeColladaPtr_t shared_ptr(new LeafNodeCollada
284
                                    (name, collada_file_path, color));
285
286
    // Add reference to itself
287
    shared_ptr->initWeakPtr(shared_ptr);
288
289
    return shared_ptr;
290
  }
291
292
  LeafNodeColladaPtr_t LeafNodeCollada::createCopy(LeafNodeColladaPtr_t other)
293
  {
294
    LeafNodeColladaPtr_t shared_ptr(new LeafNodeCollada(*other));
295
296
    // Add reference to itself
297
    shared_ptr->initWeakPtr(shared_ptr);
298
299
    return shared_ptr;
300
  }
301
302
  ::osg::NodeRefPtr LeafNodeCollada::getColladaPtr()
303
  {
304
    return collada_ptr_.get();
305
  }
306
307
  /* End of declaration of protected function members */
308
309
  /* Declaration of public function members */
310
311
  LeafNodeColladaPtr_t LeafNodeCollada::clone(void) const
312
  {
313
    return LeafNodeCollada::createCopy(weak_ptr_.lock());
314
  }
315
316
  LeafNodeColladaPtr_t LeafNodeCollada::self(void) const
317
  {
318
    return weak_ptr_.lock();
319
  }
320
321
  void LeafNodeCollada::setColor(const osgVector4& color)
322
  {
323
    osg::ref_ptr<osg::Material> mat_ptr (new osg::Material);
324
    osgVector4 ambient (color.r() * 0.5f, color.g() * 0.5f, color.b() * 0.5f, color.a());
325
326
    mat_ptr->setDiffuse (osg::Material::FRONT_AND_BACK,color);
327
    mat_ptr->setAmbient (osg::Material::FRONT_AND_BACK,ambient);
328
329
    osg::StateSet* ss = group_ptr_->getOrCreateStateSet();
330
    ss->setAttribute(mat_ptr.get());
331
    setTransparentRenderingBin (color[3] < Node::TransparencyRenderingBinThreshold, ss);
332
    setDirty();
333
  }
334
335
  osgVector4 LeafNodeCollada::getColor() const
336
  {
337
    osg::StateSet* ss = group_ptr_->getStateSet();
338
    if (ss) {
339
      osg::Material *mat = dynamic_cast<osg::Material*>
340
        (ss->getAttribute(osg::StateAttribute::MATERIAL));
341
      if (mat) return mat->getDiffuse(osg::Material::FRONT_AND_BACK);
342
    }
343
    return osgVector4(1.,1.,1.,1.);
344
  }
345
346
  void LeafNodeCollada::setAlpha(const float& alpha)
347
  {
348
    // TODO this overload is probably not necessary.
349
    osg::StateSet* ss = group_ptr_->getOrCreateStateSet();
350
351
    alpha_ = alpha;
352
    osg::Material *mat;
353
    if (ss->getAttribute(osg::StateAttribute::MATERIAL))
354
      mat = dynamic_cast<osg::Material*>(ss->getAttribute(osg::StateAttribute::MATERIAL));
355
    else {
356
      mat = new osg::Material;
357
      ss->setAttribute(mat);
358
    }
359
    mat->setAlpha(osg::Material::FRONT_AND_BACK, alpha);
360
    setTransparentRenderingBin (alpha < Node::TransparencyRenderingBinThreshold, ss);
361
    setDirty();
362
  }
363
364
  void LeafNodeCollada::setTexture(const std::string& image_path)
365
  {
366
    texture_file_path_ = image_path;
367
    osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
368
    texture->setDataVariance(osg::Object::STATIC);
369
    osg::ref_ptr<osg::Image> image = osgDB::readImageFile(image_path);
370
    if (!image)
371
    {
372
      std::cout << " couldn't find texture, quiting." << std::endl;
373
      return;
374
    }
375
    texture->setImage(image);
376
    collada_ptr_->getOrCreateStateSet()->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
377
    setDirty();
378
  }
379
380
  const std::string& LeafNodeCollada::meshFilePath () const
381
  {
382
    return collada_file_path_;
383
  }
384
385
  const std::string& LeafNodeCollada::textureFilePath () const
386
  {
387
    return texture_file_path_;
388
  }
389
390
  /*void LeafNodeCollada::setColor(osg::NodeRefPtr osgNode_ptr,const osgVector4& color)
391
  {
392
    osg::Vec4ArrayRefPtr colorArray = new osg::Vec4Array();
393
    colorArray->push_back(color);
394
    osg::GeodeRefPtr geode_ptr = osgNode_ptr->asGeode();
395
    if (geode_ptr) {
396
      for (unsigned int i = 0 ; i < geode_ptr->getNumDrawables() ; i++) {
397
      osg::GeometryRefPtr geom_ptr = geode_ptr->getDrawable(i)->asGeometry();
398
        if (geom_ptr) {
399
          geom_ptr->setColorArray(colorArray.get());
400
          geom_ptr->setColorBinding(osg::Geometry::BIND_OVERALL);
401
        }
402
      }
403
    }
404
    else {
405
      osg::GroupRefPtr group_ptr = osgNode_ptr->asGroup();
406
      if (group_ptr) {
407
        for (unsigned int i = 0 ; i < group_ptr->getNumChildren() ; i++) {
408
          setColor(group_ptr->getChild(i),color);
409
        }
410
      }
411
    }
412
  }*/
413
414
  osg::ref_ptr<osg::Node> LeafNodeCollada::getOsgNode() const
415
  {
416
    return collada_ptr_;
417
  }
418
419
  void LeafNodeCollada::removeLightSources ()
420
  {
421
    LightSourceRemoving lsRemoving;
422
    collada_ptr_->traverse (lsRemoving);
423
  }
424
425
  LeafNodeCollada::~LeafNodeCollada()
426
  {
427
    /* Proper deletion of all tree scene */
428
    group_ptr_->removeChild(collada_ptr_);
429
430
    if (collada_ptr_->referenceCount() == 2) {
431
      // If the object is only referenced by this node and the cache,
432
      // remove it from the cache.
433
#if OSG_VERSION_LESS_THAN(3,3,3)
434
      object_cache.erase(collada_file_path_);
435
#else
436
      object_cache->removeFromObjectCache(collada_file_path_);
437
#endif
438
    }
439
440
    collada_ptr_ = NULL;
441
442
    weak_ptr_.reset();
443
  }
444
445
  /* End of declaration of public function members */
446
447
} /* namespace viewer */
448
449

3
} /* namespace gepetto */