GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/leaf-node-collada.cpp Lines: 0 203 0.0 %
Date: 2024-04-14 11:13:22 Branches: 0 392 0.0 %

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