GCC Code Coverage Report


Directory: ./
File: src/leaf-node-collada.cpp
Date: 2024-12-20 15:53:58
Exec Total Coverage
Lines: 0 204 0.0%
Branches: 0 398 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 */
460