MEPP2 Project
MeshLoading.inl
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published
6 // by the Free Software Foundation; either version 3 of the License,
7 // or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 
13 #include <osg/ShadeModel>
14 #include <osgUtil/Optimizer>
15 
16 #include <memory>
17 
19 #include "FEVV/Types/Material.h"
20 
21 
22 // TODO : REVOIR les osg::StateAttribute::OVERRIDE et les vĂ©rifier !!!
23 
24 struct CameraPosCallback : public osg::Uniform::Callback
25 {
26  explicit CameraPosCallback(osg::Camera *camera) : camera{camera} {}
27 
28  virtual void operator()(osg::Uniform *uniform,
29  osg::NodeVisitor * /*nodeVisitor*/) override
30  {
31  uniform->set(osg::Vec3(camera->getInverseViewMatrix().getTrans()));
32  }
33 
34  osg::Camera *camera;
35 };
36 
37 struct CameraTargetCallback : public osg::Uniform::Callback
38 {
39  explicit CameraTargetCallback(osg::Geode *geode) : geode{geode} {}
40 
41  virtual void operator()(osg::Uniform *uniform,
42  osg::NodeVisitor * /*nodeVisitor*/) override
43  {
44  uniform->set(geode->getBound().center());
45 
46  // The bounding box being never recomputed, this line should work although
47  // less accurate
48  // uniform->set(osg::Vec3(osg::computeLocalToWorld(nodeVisitor->getNodePath()).getTrans()));
49  }
50 
51  osg::Geode *geode;
52 };
53 
54 struct ModelMatrixCallback : public osg::Uniform::Callback
55 {
56  virtual void operator()(osg::Uniform *uniform,
57  osg::NodeVisitor *nodeVisitor) override
58  {
59  uniform->set(osg::computeLocalToWorld(nodeVisitor->getNodePath()));
60  }
61 };
62 
63 struct ViewMatrixCallback : public osg::Uniform::Callback
64 {
65  explicit ViewMatrixCallback(osg::Camera *camera) : camera{camera} {}
66 
67  virtual void operator()(osg::Uniform *uniform,
68  osg::NodeVisitor * /*nodeVisitor*/) override
69  {
70  uniform->set(osg::Matrix(camera->getViewMatrix()));
71  }
72 
73  osg::Camera *camera;
74 };
75 
76 struct InverseViewMatrixCallback : public osg::Uniform::Callback
77 {
78  explicit InverseViewMatrixCallback(osg::Camera *camera) : camera{camera} {}
79 
80  virtual void operator()(osg::Uniform *uniform,
81  osg::NodeVisitor * /*nodeVisitor*/) override
82  {
83  uniform->set(osg::Matrix(camera->getInverseViewMatrix()));
84  }
85 
86  osg::Camera *camera;
87 };
88 
89 struct ProjectionMatrixCallback : public osg::Uniform::Callback
90 {
91  explicit ProjectionMatrixCallback(osg::Camera *camera) : camera{camera} {}
92 
93  virtual void operator()(osg::Uniform *uniform,
94  osg::NodeVisitor * /*nodeVisitor*/) override
95  {
96  uniform->set(osg::Matrix(camera->getProjectionMatrix()));
97  }
98 
99  osg::Camera *camera;
100 };
101 
102 struct MVPMatrixCallback : public osg::Uniform::Callback
103 {
104  explicit MVPMatrixCallback(osg::Camera *camera) : camera{camera} {}
105 
106  virtual void operator()(osg::Uniform *uniform,
107  osg::NodeVisitor *nodeVisitor) override
108  {
109  const auto viewMatrix = camera->getViewMatrix();
110  const auto modelMatrix =
111  osg::computeLocalToWorld(nodeVisitor->getNodePath());
112  const auto mvpMatrix =
113  modelMatrix * viewMatrix * camera->getProjectionMatrix();
114 
115  uniform->set(mvpMatrix);
116  }
117 
118  osg::Camera *camera;
119 };
120 
121 inline std::string
123 {
124  auto baseDir = QDir(QApplication::applicationDirPath());
125 
126 #if defined(Q_OS_MAC)
127  if(baseDir.dirName() == "MacOS")
128  {
129  baseDir.cdUp();
130  baseDir.cdUp();
131  baseDir.cdUp();
132  }
133 #endif
134 
135  return baseDir.absolutePath().toStdString();
136 }
137 
138 inline osg::ref_ptr< osg::Texture2D >
139 createDefaultTexture(uint8_t value = 255) // white by default
140 {
141  osg::ref_ptr< osg::Image > img = new osg::Image();
142  img->allocateImage(1, 1, 1, GL_RGB, GL_UNSIGNED_BYTE);
143 
144  const osg::Vec3ub color(value, value, value);
145  const auto imgData = reinterpret_cast< osg::Vec3ub * >(img->data());
146  *imgData = color;
147 
148  osg::ref_ptr< osg::Texture2D > texture = new osg::Texture2D();
149  texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
150  texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
151  texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
152  texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
153  texture->setImage(img);
154 
155  return texture;
156 }
157 
158 
162 inline
163 void
165 {
166  const unsigned char *imgdata = osgimg.data();
167  unsigned int channels =
168  osgimg.getTotalDataSize() / (osgimg.s() * osgimg.t() * osgimg.r());
169 
170  std::cout << "----------------------------\n";
171  std::cout << "OSG image info:\n";
172  std::cout << " width " << osgimg.s() << '\n';
173  std::cout << " height " << osgimg.t() << '\n';
174  std::cout << " depth " << osgimg.r() << '\n';
175  std::cout << " channels " << channels << '\n';
176  std::cout << " contig. " << osgimg.isDataContiguous() << '\n';
177  std::cout << " dataSz " << osgimg.getTotalDataSize() << '\n';
178  std::cout << " data() " << static_cast< const void* >(osgimg.data())
179  << '\n';
180  std::cout << " data[] ";
181  // print the two 1st pixels of the two 1st lines
182  for(unsigned int l = 0; l < 2; l++)
183  {
184  const unsigned char *linedata = imgdata + l*osgimg.s()*channels;
185 
186  for(unsigned int i = 0; i < 2*channels; i++) // 2x RGB[A] tuples
187  {
188  std::cout << ' ' << (int)linedata[i];
189  }
190 
191  std::cout << "...\n" << " ";
192  }
193  std::cout << " ...\n";
194  std::cout << "----------------------------\n";
195 }
196 
197 
201 inline
202 void
203 print_cimg_info(const cimg_library::CImg< unsigned char > &cimg)
204 {
205  const unsigned char *imgdata = cimg.data();
206 
207  std::cout << "----------------------------\n";
208  std::cout << "CImg image info:\n";
209  std::cout << " width " << cimg.width() << '\n';
210  std::cout << " height " << cimg.height() << '\n';
211  std::cout << " depth " << cimg.depth() << '\n';
212  std::cout << " channels " << cimg.spectrum() << '\n';
213  std::cout << " data() " << static_cast< const void* >(cimg.data())
214  << '\n';
215  std::cout << " data[] ";
216  // print the 1st pixels of the two 1st lines (of the 1st channel,
217  // because data are in planar order with CImg)
218  for(unsigned int l = 0; l < 2; l++)
219  {
220  const unsigned char *linedata = imgdata + l*cimg.width();
221 
222  for(unsigned int i = 0; i < 3; i++) // 3x R values
223  {
224  std::cout << ' ' << (int)linedata[i];
225  }
226 
227  std::cout << "...\n" << " ";
228  }
229  std::cout << " ...\n";
230  std::cout << "----------------------------\n";
231 }
232 
233 
238 inline
239 osg::Image*
240 cimg_to_osgimg(const cimg_library::CImg< unsigned char > &cimg)
241 {
242  // CImg pixels are in planar order (RRR..GGG..BBB..AAA..) and image data
243  // start at the upper-left corner of the image, see
244  // https://cimg.eu/reference/storage.html.
245  // OSG/OpenGL texture image pixels are in interleaved order (RGBARGBA..) and
246  // image data start at the bottom-left corner of the image.
247 
248  // sanity checks
249  if(cimg.depth() != 1)
250  {
251  std::cout << "WARNING: cimg_to_osgimg: unsupported image depth = "
252  << cimg.depth() << "." << std::endl;
253  return nullptr;
254  }
255  else if(cimg.spectrum() != 3 && cimg.spectrum() != 4)
256  {
257  std::cout << "WARNING: cimg_to_osgimg: unsupported image channels = "
258  << cimg.spectrum() << "." << std::endl;
259  return nullptr;
260  }
261 
262  // retrieve CImg input image data
263  bool alpha = (cimg.spectrum() == 4);
264  const unsigned char *cimg_r_ptr = cimg.data(0, 0, 0, 0); // R plan
265  const unsigned char *cimg_g_ptr = cimg.data(0, 0, 0, 1); // G plan
266  const unsigned char *cimg_b_ptr = cimg.data(0, 0, 0, 2); // B plan
267  const unsigned char *cimg_a_ptr =
268  (alpha) ? cimg.data(0, 0, 0, 3) : nullptr; // A plan
269 
270  // create OSG output image
271  osg::Image *osgimg = new osg::Image;
272  auto osg_pix_format = (alpha) ? GL_RGBA : GL_RGB;
273  osgimg->allocateImage(cimg.width(), cimg.height(), cimg.depth(),
274  osg_pix_format, GL_UNSIGNED_BYTE);
275  unsigned char *osg_data = osgimg->data();
276 
277  // copy CImg pixels into OSG image
278 
279  unsigned int w = cimg.width();
280  unsigned int h = cimg.height();
281  unsigned int ch = cimg.spectrum(); // number of channels
282 
283  for(unsigned int l = 0; l < h; l++) // loop over lines
284  {
285  // beginning of the line in OSG Image storage (reversed line order
286  // compared to CImg)
287  unsigned char *osg_ptr = osg_data + w*(h-1-l)*ch;
288 
289  for(unsigned int c = 0; c < w; c++) // loop over columns
290  {
291  // copy pixel
292  *osg_ptr = *cimg_r_ptr;
293  osg_ptr++;
294  *osg_ptr = *cimg_g_ptr;
295  osg_ptr++;
296  *osg_ptr = *cimg_b_ptr;
297  osg_ptr++;
298 
299  if(alpha)
300  {
301  *osg_ptr = *cimg_a_ptr;
302  osg_ptr++;
303  cimg_a_ptr++;
304  }
305 
306  // the inner loop is over columns ; the data are in the right order
307  // in CImg, so increasing CImg pointers is enough
308  cimg_r_ptr++;
309  cimg_g_ptr++;
310  cimg_b_ptr++;
311  }
312  }
313 
314  return osgimg;
315 }
316 
317 
318 inline osg::ref_ptr< osg::Texture2D >
319 createTexture(const std::string &filename,
320  const FEVV::Types::Material &material)
321 {
322  osg::ref_ptr< osg::Texture2D > texture;
323 
324  //DBG std::cout << "##########################" << std::endl;
325  //DBG std::cout << "# READ TEXTURE IMAGE 1 #" << std::endl;
326  //DBG std::cout << "##########################" << std::endl;
327 
328  // retrieve texture image from material
329  auto &cimg = material.images.at(filename);
330  // note: can not use material.images[filename] here because it would
331  // discard the constness
332  //DBG print_cimg_info(*cimg);
333 
334  // convert CImg image to OSG image
335  osg::ref_ptr< osg::Image > image = cimg_to_osgimg(*cimg);
336  //DBG print_osg_img_info(*image);
337 
338  if(image)
339  {
340  // std::cout << "[MeshLoading] Texture file '" << _texture_file << "'
341  // loaded." << std::endl;
342 
343  texture = new osg::Texture2D;
344 
345  // protect from being optimized away as static state
346  texture->setDataVariance(osg::Object::STATIC); // previously DYNAMIC
347 
348  // assign the texture to the image we read from file
349  texture->setImage(image);
350 
351  texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
352  texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
353  texture->setFilter(osg::Texture2D::MIN_FILTER,
354  osg::Texture2D::LINEAR_MIPMAP_LINEAR);
355  texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
356  }
357  else
358  {
359  std::cerr << "-> [MeshLoading] Couldn't find texture file, creating "
360  "default texture."
361  << std::endl;
362  texture = createDefaultTexture();
363  }
364 
365  return texture;
366 }
367 
368 inline void
369 loadMaterialStandard(const osg::ref_ptr< osg::Geometry > &geometry,
370  const FEVV::Types::Material &material)
371 {
372  uint8_t map_index = 0;
373 
374  geometry->getOrCreateStateSet()->addUniform(
375  new osg::Uniform("uniMaterial.ambientMap", 0));
376  geometry->getOrCreateStateSet()->addUniform(
377  new osg::Uniform("uniMaterial.diffuseMap", 1));
378  geometry->getOrCreateStateSet()->addUniform(
379  new osg::Uniform("uniMaterial.specularMap", 2));
380  geometry->getOrCreateStateSet()->addUniform(
381  new osg::Uniform("uniMaterial.emissiveMap", 3));
382  geometry->getOrCreateStateSet()->addUniform(
383  new osg::Uniform("uniMaterial.transparencyMap", 4));
384  geometry->getOrCreateStateSet()->addUniform(
385  new osg::Uniform("uniMaterial.bumpMap", 5));
386 
387  for(const auto &texture_filename : {material.ambient_texture_filename,
388  material.diffuse_texture_filename,
389  material.specular_texture_filename,
390  material.emissive_texture_filename,
392  material.normal_map_filename})
393  {
394  osg::ref_ptr< osg::Texture2D > texture;
395 
396  if(!texture_filename.empty())
397  texture = createTexture(texture_filename, material);
398  else
399  texture = createDefaultTexture((map_index == 3 ? 0 : 255));
400  // Little hack here: for emissive map, create
401  // a black texture instead of a white
402 
403  geometry->getOrCreateStateSet()->setTextureAttribute(
404  map_index,
405  texture,
406  osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
407  ++map_index;
408  }
409 }
410 
411 inline void
412 loadMaterialPBR(const osg::ref_ptr< osg::Geometry > &geometry,
413  const FEVV::Types::Material &material)
414 {
415  uint8_t map_index = 0;
416 
417  geometry->getOrCreateStateSet()->addUniform(
418  new osg::Uniform("uniMaterial.albedoMap", 0));
419  geometry->getOrCreateStateSet()->addUniform(
420  new osg::Uniform("uniMaterial.normalMap", 1));
421  geometry->getOrCreateStateSet()->addUniform(
422  new osg::Uniform("uniMaterial.metallicMap", 2));
423  geometry->getOrCreateStateSet()->addUniform(
424  new osg::Uniform("uniMaterial.roughnessMap", 3));
425  geometry->getOrCreateStateSet()->addUniform(
426  new osg::Uniform("uniMaterial.emissiveMap", 4));
427  geometry->getOrCreateStateSet()->addUniform(
428  new osg::Uniform("uniMaterial.ambientOcclusionMap", 5));
429 
430  for(const auto &texture_filename : {material.diffuse_texture_filename,
431  material.normal_map_filename,
432  material.metallic_map_filename,
433  material.roughness_map_filename,
434  material.emissive_texture_filename,
435  material.ambient_texture_filename})
436  {
437  osg::ref_ptr< osg::Texture2D > texture;
438 
439  if(!texture_filename.empty())
440  texture = createTexture(texture_filename, material);
441  else
442  texture = createDefaultTexture((map_index == 4 ? 0 : 255));
443  // Little hack here: for emissive map, create
444  // a black texture instead of a white
445 
446  geometry->getOrCreateStateSet()->setTextureAttribute(
447  map_index,
448  texture,
449  osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
450  ++map_index;
451  }
452 }
453 
454 template< typename VertexNormalMap,
455  typename VertexTangentMap,
456  typename FaceMaterialMap >
457 inline osg::ref_ptr< osg::Program >
459  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries,
460  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_vertexArrays*/,
461  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_normalsArrays*/,
462  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_tangentsArrays,
463  const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays,
464  bool _useSmoothShading,
465  VertexNormalMap * /*_vt_nm*/,
466  VertexTangentMap *_vt_tm,
467  FaceMaterialMap *_m_mm,
468  std::size_t unit_ii)
469 {
470  const auto &shadersDirectory = recoverBaseDirectory() + "/Shaders/";
471  osg::ref_ptr< osg::Program > program = new osg::Program;
472 
473  osg::ref_ptr< osg::Shader > vertShader = new osg::Shader(osg::Shader::VERTEX);
474  if(!vertShader->loadShaderSourceFromFile(shadersDirectory + "vert.glsl"))
475  std::cerr << "[MeshLoading] Could not read VERTEX shader from file"
476  << std::endl;
477  program->addShader(vertShader);
478 
479  // RM: disabled these calls, fixing loading time & FPS problems
480  //_geometries[unit_ii]->setUseVertexBufferObjects(true);
481 
482  // Sending texcoords to shader
483  _geometries[unit_ii]->setVertexAttribArray(
484  1, _texcoordsArrays[unit_ii], osg::Array::BIND_PER_VERTEX);
485 
486  // Sending tangents to shader (no need if we're rendering in flat shading)
487  if(_vt_tm != nullptr && _useSmoothShading)
488  _geometries[unit_ii]->setVertexAttribArray(
489  3, _tangentsArrays[unit_ii], osg::Array::BIND_PER_VERTEX);
490 
491  std::string fragShaderLocation =
492  shadersDirectory + "blinn-phong.glsl"; // Shader by default
493 
494  const auto &material = get(*_m_mm, unit_ii);
495  if(!material.name.empty()) // Normally, 'empty' is not possible here (would be
496  // a colored mesh)
497  {
499  {
500  fragShaderLocation = shadersDirectory + "cook-torrance.glsl";
501 
502  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
503  new osg::Uniform("uniMaterial.baseColor",
504  osg::Vec3f(material.diffuse_red_component,
505  material.diffuse_green_component,
506  material.diffuse_blue_component)));
507  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
508  new osg::Uniform("uniMaterial.metallicFactor",
509  static_cast< float >(material.metallic_factor)));
510  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
511  new osg::Uniform("uniMaterial.roughnessFactor",
512  static_cast< float >(material.roughness_factor)));
513  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
514  new osg::Uniform("uniMaterial.emissive",
515  osg::Vec3f(material.emissive_red_component,
516  material.emissive_green_component,
517  material.emissive_blue_component)));
518 
519  loadMaterialPBR(_geometries[unit_ii], material);
520  }
521  else
522  {
523  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
524  new osg::Uniform("uniMaterial.ambient",
525  osg::Vec3f(material.ambient_red_component,
526  material.ambient_green_component,
527  material.ambient_blue_component)));
528  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
529  new osg::Uniform("uniMaterial.diffuse",
530  osg::Vec3f(material.diffuse_red_component,
531  material.diffuse_green_component,
532  material.diffuse_blue_component)));
533  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
534  new osg::Uniform("uniMaterial.specular",
535  osg::Vec3f(material.specular_red_component,
536  material.specular_green_component,
537  material.specular_blue_component)));
538  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
539  new osg::Uniform("uniMaterial.emissive",
540  osg::Vec3f(material.emissive_red_component,
541  material.emissive_green_component,
542  material.emissive_blue_component)));
543  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
544  new osg::Uniform("uniMaterial.transparency",
545  static_cast< float >(material.transparency)));
546 
547  loadMaterialStandard(_geometries[unit_ii], material);
548  }
549 
550  if(material.has_normal_map && _useSmoothShading)
551  _geometries[unit_ii]->getOrCreateStateSet()->addUniform(
552  new osg::Uniform("uniUseNormalMapping", true));
553  }
554 
555  osg::ref_ptr< osg::Shader > fragShader =
556  new osg::Shader(osg::Shader::FRAGMENT);
557  if(!fragShader->loadShaderSourceFromFile(fragShaderLocation))
558  std::cerr << "[MeshLoading] Could not read FRAGMENT shader from file"
559  << std::endl;
560 
561  program->addShader(fragShader);
562 
563  return program;
564 }
565 
566 template< typename VertexNormalMap, typename VertexColorMap >
567 inline osg::ref_ptr< osg::Program >
569  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries,
570  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_vertexArrays*/,
571  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_normalsArrays*/,
572  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays,
573  VertexNormalMap * /*_vt_nm*/,
574  VertexColorMap *_vt_cm,
575  std::size_t unit_ii)
576 {
577  const auto &shadersDirectory = recoverBaseDirectory() + "/Shaders/";
578  osg::ref_ptr< osg::Program > program = new osg::Program;
579 
580  osg::ref_ptr< osg::Shader > vertShader = new osg::Shader(osg::Shader::VERTEX);
581  if(!vertShader->loadShaderSourceFromFile(shadersDirectory + "colorVert.glsl"))
582  std::cerr << "[MeshLoading] Could not read VERTEX shader from file"
583  << std::endl;
584  program->addShader(vertShader);
585 
586  osg::ref_ptr< osg::Shader > fragShader =
587  new osg::Shader(osg::Shader::FRAGMENT);
588  if(!fragShader->loadShaderSourceFromFile(shadersDirectory + "colorFrag.glsl"))
589  std::cerr << "[MeshLoading] Could not read FRAGMENT shader from file"
590  << std::endl;
591  program->addShader(fragShader);
592 
593  // RM: disabled these calls, fixing loading time & FPS problems
594  //_geometries[unit_ii]->setUseVertexBufferObjects(true);
595 
596  // Sending colors to shader
597  _geometries[unit_ii]->setVertexAttribArray(
598  1,
599  _colorsArrays[unit_ii],
600  (_vt_cm != nullptr ? osg::Array::BIND_PER_VERTEX
601  : osg::Array::BIND_PER_PRIMITIVE_SET));
602 
603  return program;
604 }
605 
606 template< typename HalfedgeGraph,
607  typename VertexNormalMap,
608  typename VertexTangentMap,
609  typename VertexColorMap,
610  typename FaceColorMap,
611  typename VertexUVMap,
612  typename HalfedgeUVMap,
613  typename FaceMaterialMap >
614 void
616  osg::Geode *_geode,
617  HalfedgeGraph *_g,
618  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries,
619  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_edges,
620  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_vertices,
621  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_normals,
622  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_custom_vectors,
623  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays,
624  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_edges,
625  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_vertices,
626  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_normals,
627  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_custom_vectors,
628  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays,
629  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_edges,
630  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_vertices,
631  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_tangentsArrays,
632  const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays,
633  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays,
634  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_edges,
635  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_vertices,
636  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_normals,
637  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_custom_vectors,
638  std::size_t _m_mm_size,
639  VertexNormalMap *_vt_nm,
640  VertexTangentMap *_vt_tm,
641  VertexColorMap *_vt_cm,
642  FaceColorMap *_f_cm,
643  VertexUVMap *_vt_uv_m,
644  HalfedgeUVMap *_het_uv_m,
645  FaceMaterialMap *_m_mm,
646  bool has_face_color_map)
647 {
648  std::cout << "[MeshLoading] Loading using shaders." << std::endl;
649 
650  const auto &shadersDirectory = recoverBaseDirectory() + "/Shaders/";
651 
652  std::vector< osg::ref_ptr< osg::Vec4Array > > colorsArrays2;
653 
654  size_t unit_ii = 0;
655  do
656  {
657  _geometries[unit_ii]->setStateSet(NULL); // NEW
658  _geometries[unit_ii]->setColorArray(NULL); // NEW
659 
660  osg::ref_ptr< osg::Program > program;
661 
662  // Sending positions to shader
663  _geometries[unit_ii]->setVertexAttribArray(
664  0, _vertexArrays[unit_ii], osg::Array::BIND_PER_VERTEX);
665 
666  // Sending normals to shader
667  _geometries[unit_ii]->setVertexAttribArray(
668  2,
669  _normalsArrays[unit_ii],
670  (_vt_nm != nullptr ? osg::Array::BIND_PER_VERTEX
671  : osg::Array::BIND_PER_PRIMITIVE_SET));
672 
673  // if(_colorsArrays[unit_ii].get()->empty() &&
674  if((_vt_uv_m != nullptr || _het_uv_m != nullptr) &&
675  !_texcoordsArrays[unit_ii].get()->empty())
676  {
677  program = loadTexturedMesh(_geometries,
678  _vertexArrays,
679  _normalsArrays,
680  _tangentsArrays,
681  _texcoordsArrays,
683  _vt_nm,
684  _vt_tm,
685  _m_mm,
686  unit_ii);
687  }
688  else
689  {
690  colorsArrays2.push_back(new osg::Vec4Array);
691 
692  const std::vector< osg::ref_ptr< osg::Vec4Array > > *colorsArrays_tmp;
693 
694  VertexColorMap vt_cm2;
695  VertexColorMap *vt_cm_tmp;
696 
697  if(_vt_cm != nullptr || _f_cm != nullptr)
698  {
699  colorsArrays_tmp = &_colorsArrays;
700  vt_cm_tmp = _vt_cm;
701  }
702  else
703  {
704  colorsArrays2[unit_ii].get()->resize(
705  _vertexArrays[unit_ii].get()->size(),
707 
708  colorsArrays_tmp = &colorsArrays2;
709 
710  vt_cm2 = make_property_map(FEVV::vertex_color, *_g);
711  vt_cm_tmp = &vt_cm2;
712  }
713 
714  program = loadColoredMesh(_geometries,
715  _vertexArrays,
716  _normalsArrays,
717  *colorsArrays_tmp /*_colorsArrays*/,
718  _vt_nm,
719  vt_cm_tmp /*_vt_cm*/,
720  unit_ii);
721  }
722 
723  _geometries[unit_ii]->getOrCreateStateSet()->setAttributeAndModes(
724  program.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
725 
726  size_t nb_faces = size_of_faces(*_g);
727 
728  // attach geometry to geode
729  if(nb_faces != 0) // not to be done for 'only_pts' mode
730  _geode->addDrawable(_geometries[unit_ii]);
731 
732  if(unit_ii == 0) // MUST be done only one time
735  (nb_faces == 0)) // last test for 'only_pts' mode
736  {
737  // RM: adding predefined basic shaders to display superimposed features
738  osg::ref_ptr< osg::Program > superimpProgram = new osg::Program;
739 
740  osg::ref_ptr< osg::Shader > superimpVertShader =
741  new osg::Shader(osg::Shader::VERTEX);
742  if(!superimpVertShader->loadShaderSourceFromFile(
743  shadersDirectory + "superimposeVert.glsl"))
744  std::cerr << "[MeshLoading] Could not read VERTEX shader from file"
745  << std::endl;
746  superimpProgram->addShader(superimpVertShader);
747 
748  // uncomment to use GEOMETRY shader
749  /*osg::ref_ptr< osg::Shader > superimpGeomShader =
750  new osg::Shader(osg::Shader::GEOMETRY);
751  if(!superimpGeomShader->loadShaderSourceFromFile(
752  shadersDirectory + "superimposeGeom.glsl"))
753  std::cerr << "[MeshLoading] Could not read GEOMETRY shader from file"
754  << std::endl;
755  superimpProgram->addShader(superimpGeomShader);*/
756  // uncomment to use GEOMETRY shader
757 
758  osg::ref_ptr< osg::Shader > superimpFragShader =
759  new osg::Shader(osg::Shader::FRAGMENT);
760  if(!superimpFragShader->loadShaderSourceFromFile(
761  shadersDirectory + "superimposeFrag.glsl"))
762  std::cerr << "Could not read FRAGMENT shader from file" << std::endl;
763  superimpProgram->addShader(superimpFragShader);
764 
765  // RM: loading superimposed features
766  // edges - superimpose only
768  (nb_faces != 0)) // not to be done for 'only_pts' mode
769  {
770  std::cout << "[MeshLoading] Drawing superimposed edges" << std::endl; // ADD THIS std::cout IN LEGACY mode too !!!
771 
772  // RM: disabled these calls, fixing loading time & FPS problems
773  //_geometries_edges[unit_ii]->setUseVertexBufferObjects(true);
774 
775  _geometries_edges[unit_ii]->setVertexAttribArray(
776  0, _vertexArrays_edges[unit_ii], osg::Array::BIND_PER_VERTEX);
777  _geometries_edges[unit_ii]->setVertexAttribArray(
778  1, _colorsArrays_edges[unit_ii], osg::Array::BIND_PER_VERTEX);
779  _geometries_edges[unit_ii]->setVertexAttribArray(
780  2, _normalsArrays_edges[unit_ii], osg::Array::BIND_PER_VERTEX);
781  _geometries_edges[unit_ii]
782  ->getOrCreateStateSet()
783  ->setAttributeAndModes(superimpProgram.get(),
784  osg::StateAttribute::ON |
785  osg::StateAttribute::OVERRIDE);
786 
787  _geode->addDrawable(_geometries_edges[unit_ii]);
788  }
789 
790  // vertices - superimpose and 'only_pts' mode only
792  (nb_faces == 0)) // last test for 'only_pts' mode
793  {
794  std::cout << "[MeshLoading] Drawing superimposed vertices" << std::endl; // ADD THIS std::cout IN LEGACY mode too !!!
795 
796  // RM: disabled these calls, fixing loading time & FPS problems
797  //_geometries_vertices[unit_ii]->setUseVertexBufferObjects(true);
798 
799  _geometries_vertices[unit_ii]->setVertexAttribArray(
800  0, _vertexArrays_vertices[unit_ii], osg::Array::BIND_PER_VERTEX);
801  _geometries_vertices[unit_ii]->setVertexAttribArray(
802  1, _colorsArrays_vertices[unit_ii], osg::Array::BIND_PER_VERTEX);
803  _geometries_vertices[unit_ii]->setVertexAttribArray(
804  2, _normalsArrays_vertices[unit_ii], osg::Array::BIND_PER_VERTEX);
805  _geometries_vertices[unit_ii]
806  ->getOrCreateStateSet()
807  ->setAttributeAndModes(superimpProgram.get(),
808  osg::StateAttribute::ON |
809  osg::StateAttribute::OVERRIDE);
810 
811  // RM: if bigger vertices are needed, send a default size of 5 to the
812  // shader, which will display them accordingly
813  /*if (m_RenderSuperimposedVertices_Big)
814  {
815  _geometries_vertices[unit_ii]->getOrCreateStateSet()->setMode(GL_PROGRAM_POINT_SIZE,
816  osg::StateAttribute::ON);
817  _geometries_vertices[unit_ii]->getOrCreateStateSet()->addUniform(new
818  osg::Uniform("uniPointSize", 5u));
819  }*/
820 
821  _geode->addDrawable(_geometries_vertices[unit_ii]);
822  }
823 
824  // [ normals
826  {
827  std::cout << "[MeshLoading] Drawing normals" << std::endl; // ADD THIS std::cout IN LEGACY mode too !!!
828 
829  // disabled these calls, fixing loading time & FPS problems
830  //_geometries_normals[unit_ii]->setUseVertexBufferObjects(true);
831 
832  _geometries_normals[unit_ii]->setVertexAttribArray(
833  0, _vertexArrays_normals[unit_ii], osg::Array::BIND_PER_VERTEX);
834  _geometries_normals[unit_ii]->setVertexAttribArray(
835  1, _colorsArrays_normals[unit_ii], osg::Array::BIND_PER_VERTEX);
836  _geometries_normals[unit_ii]
837  ->getOrCreateStateSet()
838  ->setAttributeAndModes(superimpProgram.get(),
839  osg::StateAttribute::ON |
840  osg::StateAttribute::OVERRIDE);
841 
842  _geode->addDrawable(_geometries_normals[unit_ii]);
843  }
844  // [ normals
845 
846  // [ custom_vectors
848  {
849  std::cout << "[MeshLoading] Drawing custom_vectors" << std::endl; // ADD THIS std::cout IN LEGACY mode too !!!
850 
851  // disabled these calls, fixing loading time & FPS problems
852  //_geometries_custom_vectors[unit_ii]->setUseVertexBufferObjects(true);
853 
854  _geometries_custom_vectors[unit_ii]->setVertexAttribArray(
855  0, _vertexArrays_custom_vectors[unit_ii], osg::Array::BIND_PER_VERTEX);
856  _geometries_custom_vectors[unit_ii]->setVertexAttribArray(
857  1, _colorsArrays_custom_vectors[unit_ii], osg::Array::BIND_PER_VERTEX);
858  _geometries_custom_vectors[unit_ii]
859  ->getOrCreateStateSet()
860  ->setAttributeAndModes(superimpProgram.get(),
861  osg::StateAttribute::ON |
862  osg::StateAttribute::OVERRIDE);
863 
864  _geode->addDrawable(_geometries_custom_vectors[unit_ii]);
865  }
866  // [ custom_vectors
867  }
868 
869  ++unit_ii;
870  } while(unit_ii < _m_mm_size);
871 
872  // RM: enable/disable lighting (enabled by default)
873  if(m_Lighting)
874  _geode->getOrCreateStateSet()->addUniform(
875  new osg::Uniform("uniUseLighting", true));
876  else
877  _geode->getOrCreateStateSet()->addUniform(
878  new osg::Uniform("uniUseLighting", false));
879 
881  _geode->getOrCreateStateSet()->addUniform(
882  new osg::Uniform("uniUseSmoothShading", false));
883 
884  std::cout << "--- Setting uniforms callbacks" << std::endl;
885 
886  // osgViewer::View* view = getView(0); // for osgViewer::CompositeViewer
887  osgViewer::View *view =
888  dynamic_cast< osgViewer::View * >(this); // for osgViewer::Viewer
889 
890 #if(FEVV_USE_QT5) // FOR_QT6
891  BaseViewer *bv = dynamic_cast< BaseViewer * >(this);
892  SimpleAdapterVisu *sav =
893  dynamic_cast< SimpleAdapterVisu * >(bv->getAdapter());
894 
895  //view = sav->my_osgQOpenGLWidget->getOsgViewer();
896  view = sav->my_osgQOpenGLWindow->getOsgViewer();
897 #endif
898 
899  // RM: setting callback for camera position
900  osg::Uniform *cameraPos =
901  new osg::Uniform(osg::Uniform::FLOAT_VEC3, "uniCameraPos");
902  cameraPos->setUpdateCallback(new CameraPosCallback(view->getCamera()));
903  _geode->getOrCreateStateSet()->addUniform(cameraPos);
904 
905  // RM: setting callback for camera target (unneeded for now since view matrix
906  // seems to embed it (theorically is a look-at))
907  /*osg::Uniform* cameraTarget = new osg::Uniform(osg::Uniform::FLOAT_VEC3,
908  "uniCameraTarget"); cameraTarget->setUpdateCallback(new
909  CameraTargetCallback(_geode));
910  _geode->getOrCreateStateSet()->addUniform(cameraTarget);*/
911 
912  // RM: setting callback for model matrix
913  osg::Uniform *modelMatrix =
914  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "uniModelMatrix");
915  modelMatrix->setUpdateCallback(new ModelMatrixCallback());
916  _geode->getOrCreateStateSet()->addUniform(modelMatrix);
917 
918  // RM: setting callback for view matrix
919  osg::Uniform *viewMatrix =
920  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "uniViewMatrix");
921  viewMatrix->setUpdateCallback(new ViewMatrixCallback(view->getCamera()));
922  _geode->getOrCreateStateSet()->addUniform(viewMatrix);
923 
924  // RM: setting callback for inverse view matrix
925  osg::Uniform *invViewMatrix =
926  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "uniInvViewMatrix");
927  invViewMatrix->setUpdateCallback(
928  new InverseViewMatrixCallback(view->getCamera()));
929  _geode->getOrCreateStateSet()->addUniform(invViewMatrix);
930 
931  // RM: setting callback for MVP matrix
932  osg::Uniform *mvpMatrix =
933  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "uniMvpMatrix");
934  mvpMatrix->setUpdateCallback(new MVPMatrixCallback(view->getCamera()));
935  _geode->getOrCreateStateSet()->addUniform(mvpMatrix);
936 
937 
938  // MTO: setting callback for model matrix
939  osg::Uniform *g_modelMatrix =
940  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "model");
941  g_modelMatrix->setUpdateCallback(new ModelMatrixCallback());
942  _geode->getOrCreateStateSet()->addUniform(g_modelMatrix);
943 
944  // MTO: setting callback for view matrix
945  osg::Uniform *g_viewMatrix =
946  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "view");
947  g_viewMatrix->setUpdateCallback(new ViewMatrixCallback(view->getCamera()));
948  _geode->getOrCreateStateSet()->addUniform(g_viewMatrix);
949 
950  // MTO: setting callback for projection matrix
951  osg::Uniform *g_projectionMatrix =
952  new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projection");
953  g_projectionMatrix->setUpdateCallback(new ProjectionMatrixCallback(view->getCamera()));
954  _geode->getOrCreateStateSet()->addUniform(g_projectionMatrix);
955 
956  /*
957  RM: creating light(s)
958  - Point light: position = x/y/z/1, no need to set direction
959  - Directional light: position = x/y/z/0, direction = x/y/z
960  (actually we don't really care about directional lights's position
961  x/y/z, except if it's to be displayed) (Stressing out: point light's
962  direction.w *must be* 1 (actually anything different than 0, but should be 1
963  for consistency), directional's *must be* 0)
964 
965  Example:
966  osg::ref_ptr<osg::Light> new_light = new osg::Light;
967 
968  new_light->setPosition(osg::Vec4(0.f, 1.f, 0.f, 1.f)); // The 1.f at the
969  end means that this is *not* a directional light
970  //new_light->setDirection(osg::Vec3(-1.f, -1.f, 0.f)); // Must be set for
971  directional light new_light->setDiffuse(osg::Vec4(1.f, 0.f, 0.f, 1.f)); //
972  Light's color (R/G/B), this one will then be red (set to 1.f/1.f/1.f to get a
973  white color); the last parameter has no influence
974  new_light->setLinearAttenuation(1.f); // Light intensity
975 
976  lights.push_back(new_light);
977  */
978 
979  // RM: sending lights to the shader
980  // This is called for every mesh; ideally, this should be done upstream
981  // *once* with a Uniform Buffer Object
982  _geode->getOrCreateStateSet()->addUniform(new osg::Uniform(
983  "uniLightCount", static_cast< unsigned int >(lights.size())));
984 
985  for(std::size_t lightIndex = 0; lightIndex < lights.size(); ++lightIndex)
986  {
987  const std::string locationBase =
988  "uniLights[" + std::to_string(lightIndex) + "].";
989 
990  const std::string posLocation = locationBase + "position";
991  const std::string dirLocation = locationBase + "direction";
992  const std::string colorLocation = locationBase + "color";
993  const std::string energyLocation = locationBase + "energy";
994 
995  _geode->getOrCreateStateSet()->addUniform(new osg::Uniform(
996  posLocation.c_str(), lights[lightIndex]->getPosition()));
997  _geode->getOrCreateStateSet()->addUniform(new osg::Uniform(
998  dirLocation.c_str(), lights[lightIndex]->getDirection()));
999  _geode->getOrCreateStateSet()->addUniform(new osg::Uniform(
1000  colorLocation.c_str(), lights[lightIndex]->getDiffuse()));
1001  _geode->getOrCreateStateSet()->addUniform(new osg::Uniform(
1002  energyLocation.c_str(), lights[lightIndex]->getLinearAttenuation()));
1003  }
1004 
1005  osgUtil::Optimizer optimizer; // https://github.com/openscenegraph/OpenSceneGraph/blob/master/include/osgUtil/Optimizer
1006  /*ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
1007  REMOVE_REDUNDANT_NODES |
1008  REMOVE_LOADED_PROXY_NODES |
1009  COMBINE_ADJACENT_LODS |
1010  SHARE_DUPLICATE_STATE |
1011  MERGE_GEODES |
1012  MERGE_GEOMETRY |
1013  MAKE_FAST_GEOMETRY |
1014  CHECK_GEOMETRY |
1015  SPATIALIZE_GROUPS |
1016  COPY_SHARED_NODES |
1017  TRISTRIP_GEOMETRY |
1018  OPTIMIZE_TEXTURE_SETTINGS |
1019  TEXTURE_ATLAS_BUILDER |
1020  STATIC_OBJECT_DETECTION |
1021  BUFFER_OBJECT_SETTINGS*/
1022 
1023  if (has_face_color_map)
1024  {
1025  #if OSG_MIN_VERSION_REQUIRED(3, 6, 0)
1026  optimizer.optimize(_geode, osgUtil::Optimizer::BUFFER_OBJECT_SETTINGS /*| osgUtil::Optimizer::MERGE_GEODES*/ /*| osgUtil::Optimizer::MERGE_GEOMETRY*/ /*| osgUtil::Optimizer::MAKE_FAST_GEOMETRY*/);
1027  #else
1028  //optimizer.optimize(_geode, osgUtil::Optimizer::MERGE_GEOMETRY);
1029  #endif
1030  }
1031  else
1032  {
1033  #if OSG_MIN_VERSION_REQUIRED(3, 6, 0)
1034  optimizer.optimize(_geode, osgUtil::Optimizer::BUFFER_OBJECT_SETTINGS /*| osgUtil::Optimizer::MERGE_GEODES*/ | osgUtil::Optimizer::MERGE_GEOMETRY /*| osgUtil::Optimizer::MAKE_FAST_GEOMETRY*/);
1035  #else
1036  optimizer.optimize(_geode, osgUtil::Optimizer::MERGE_GEOMETRY);
1037  #endif
1038  }
1039 }
1040 
1041 
1042 template< typename HalfedgeGraph,
1043  typename VertexNormalMap,
1044  typename VertexColorMap,
1045  typename FaceColorMap,
1046  typename VertexUVMap,
1047  typename HalfedgeUVMap,
1048  typename FaceMaterialMap >
1049 void
1051  osg::Geode *_geode,
1052  HalfedgeGraph *_g,
1053  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries,
1054  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_edges,
1055  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_vertices,
1056  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_normals,
1057  const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_custom_vectors,
1058  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays,
1059  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_edges,
1060  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_vertices,
1061  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_normals,
1062  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_custom_vectors,
1063  const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays,
1064  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_normalsArrays_edges*/,
1065  const std::vector< osg::ref_ptr< osg::Vec3Array > > &/*_normalsArrays_vertices*/,
1066  const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays,
1067  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays,
1068  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_edges,
1069  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_vertices,
1070  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_normals,
1071  const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_custom_vectors,
1072  std::size_t _m_mm_size,
1073  int _texture_type,
1074  VertexNormalMap *_vt_nm,
1075  VertexColorMap *_vt_cm,
1076  FaceColorMap *_f_cm,
1077  VertexUVMap *_vt_uv_m,
1078  HalfedgeUVMap *_het_uv_m,
1079  FaceMaterialMap *_m_mm,
1080  bool has_face_color_map)
1081 {
1082  std::cout << "[MeshLoading] Loading using legacy rendering." << std::endl;
1083 
1084  size_t unit_ii = 0;
1085  do
1086  {
1087  _geometries[unit_ii]->setStateSet(NULL); // NEW
1088  _geometries[unit_ii]->setColorArray(NULL); // NEW
1089 
1090  _geometries[unit_ii]->setVertexArray(_vertexArrays[unit_ii]);
1091  if(_vt_nm != nullptr)
1092  {
1093  _geometries[unit_ii]->setNormalArray(_normalsArrays[unit_ii],
1094  osg::Array::BIND_PER_VERTEX);
1095  }
1096  else
1097  {
1098  _geometries[unit_ii]->setNormalArray(_normalsArrays[unit_ii],
1099  osg::Array::BIND_PER_PRIMITIVE_SET);
1100  }
1101  if(_vt_cm != nullptr)
1102  {
1103  _geometries[unit_ii]->setColorArray(_colorsArrays[unit_ii],
1104  osg::Array::BIND_PER_VERTEX);
1105  }
1106  else if(_f_cm != nullptr)
1107  {
1108  _geometries[unit_ii]->setColorArray(_colorsArrays[unit_ii],
1109  osg::Array::BIND_PER_PRIMITIVE_SET);
1110  }
1111  // TEXTURES
1112  else if((_het_uv_m != nullptr || _vt_uv_m != nullptr) &&
1113  (_texture_type == VERTEX_TEXCOORDS2D ||
1114  _texture_type == HALFEDGE_TEXCOORDS2D))
1115  {
1116  auto material = get(*_m_mm, unit_ii);
1117 
1118  osg::ref_ptr< osg::Material > Kdmaterial = new osg::Material;
1119  Kdmaterial->setDiffuse(osg::Material::FRONT,
1120  osg::Vec4(material.diffuse_red_component,
1121  material.diffuse_green_component,
1122  material.diffuse_blue_component,
1123  1.));
1124  _geometries[unit_ii]->getOrCreateStateSet()->setAttribute(
1125  Kdmaterial /*, osg::StateAttribute::OVERRIDE*/);
1126 
1127  if(!material.diffuse_texture_filename.empty())
1128  {
1129  //DBG std::cout << "##########################" << std::endl;
1130  //DBG std::cout << "# READ TEXTURE IMAGE 2 #" << std::endl;
1131  //DBG std::cout << "##########################" << std::endl;
1132 
1133  // retrieve texture image from material
1134  auto &cimg = material.images[material.diffuse_texture_filename];
1135  //DBG print_cimg_info(*cimg);
1136 
1137  // convert CImg image to OSG image
1138  osg::ref_ptr< osg::Image > image = cimg_to_osgimg(*cimg);
1139  //DBG print_osg_img_info(*image);
1140 
1141  if(image)
1142  {
1143  // std::cout << "[MeshLoading] Texture file '" << _texture_file << "'
1144  // loaded." << std::endl;
1145 
1146  osg::ref_ptr< osg::Texture2D > texture = new osg::Texture2D;
1147 
1148  // protect from being optimized away as static state
1149  texture->setDataVariance(osg::Object::STATIC); // previously DYNAMIC
1150 
1151  // assign the texture to the image we read from file
1152  texture->setImage(image);
1153 
1154  texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
1155  texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
1156  texture->setFilter(
1157  osg::Texture2D::MIN_FILTER,
1158  osg::Texture2D::LINEAR_MIPMAP_LINEAR); // previously LINEAR but
1159  // artifacts !
1160  texture->setFilter(osg::Texture2D::MAG_FILTER,
1161  osg::Texture2D::LINEAR);
1162 
1163  // NEW version - without new StateSet - assign texture unit '0' to the
1164  // texture we just created and enable the texture
1165  _geometries[unit_ii]->getOrCreateStateSet()->setAttribute(
1166  new osg::
1167  Material /*, osg::StateAttribute::OVERRIDE*/); // IMPORTANT,
1168  // pour
1169  // suppression
1170  // de l'ancien
1171  // material
1172  // (OSX PB -
1173  // SPACE MODE)
1174  _geometries[unit_ii]
1175  ->getOrCreateStateSet()
1176  ->setTextureAttributeAndModes(
1177  0 /*unit_ii*/, texture, osg::StateAttribute::ON);
1178 
1179  _geometries[unit_ii]->setTexCoordArray(0 /*unit_ii*/,
1180  _texcoordsArrays[unit_ii]);
1181  }
1182  else
1183  {
1184  std::cerr << "-> [SimpleViewer] Couldn't find texture file: "
1185  << material.diffuse_texture_filename << std::endl;
1186  }
1187  }
1188  }
1189  // MATERIAL
1190  else
1191  {
1192 #if 1
1193  // single side painting
1194 
1195  osg::ref_ptr< osg::Material > Kdmaterial = new osg::Material;
1196  Kdmaterial->setDiffuse(osg::Material::FRONT,
1198  _geometries[unit_ii]->getOrCreateStateSet()->setAttribute(
1199  Kdmaterial /*, osg::StateAttribute::OVERRIDE*/);
1200 #else
1201  // both side painting
1202 
1203  osg::ref_ptr< osg::LightModel > lightModel = new osg::LightModel;
1204  // http://www.glprogramming.com/red/chapter05.html
1205  // "OpenGL reverses the surface normals for back-facing polygons;
1206  // typically, this means that the surface normals of visible back- and
1207  // front-facing polygons face the viewer, rather than pointing away. As a
1208  // result, all polygons are illuminated correctly. However, these
1209  // additional operations usually make two-sided lighting perform more
1210  // slowly than the default one-sided lighting."
1211  lightModel->setTwoSided(true);
1212  // http://www.opengl.org/sdk/docs/man2/xhtml/glLightModel.xml
1213  // "GL_SINGLE_COLOR specifies that a single color is generated from the
1214  // lighting computation for a vertex. GL_SEPARATE_SPECULAR_COLOR
1215  // specifies that the specular color computation of lighting be stored
1216  // separately from the remainder of the lighting computation. The specular
1217  // color is summed into the generated fragment's color after the
1218  // application of texture mapping (if enabled). The initial value is
1219  // GL_SINGLE_COLOR."
1220  lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
1221  // as of 2.9.9 this would be the default
1222  lightModel->setAmbientIntensity(osg::Vec4(0.2f, 0.2f, 0.2f, 1.0f));
1223  // http://www.glprogramming.com/red/chapter05.html
1224  // "A local viewpoint tends to yield more realistic results, but since the
1225  // direction has to be calculated for each vertex, overall performance is
1226  // decreased with a local viewpoint. By default, an infinite viewpoint is
1227  // assumed."
1228  lightModel->setLocalViewer(false);
1229 
1230  geode->getOrCreateStateSet()->setAttributeAndModes(
1231  lightModel.get()); // now not geode but geometries[unit_ii] !!!
1232 #endif
1233  }
1234 
1235  size_t nb_faces = size_of_faces(*_g);
1236 
1237  // attach geometry to geode
1238  if(nb_faces != 0) // not to be done for 'only_pts' mode
1239  _geode->addDrawable(_geometries[unit_ii]);
1240 
1241  // edges - superimpose only
1242  if(unit_ii == 0) // MUST be done only one time
1243  if(m_RenderSuperimposedEdges &&
1244  (nb_faces != 0)) // not to be done for 'only_pts' mode
1245  {
1246  _geometries_edges[unit_ii]->setVertexArray(
1247  _vertexArrays_edges[unit_ii]);
1248  _geometries_edges[unit_ii]->setColorArray(_colorsArrays_edges[unit_ii],
1249  osg::Array::BIND_PER_VERTEX);
1250  _geode->addDrawable(_geometries_edges[unit_ii]);
1251  }
1252 
1253  // vertices - superimpose and 'only_pts' mode only
1254  if(unit_ii == 0) // MUST be done only one time
1255  if(m_RenderSuperimposedVertices || m_RenderSuperimposedVertices_Big ||
1256  (nb_faces == 0)) // last test for 'only_pts' mode
1257  {
1258  _geometries_vertices[unit_ii]->setVertexArray(
1259  _vertexArrays_vertices[unit_ii]);
1260  _geometries_vertices[unit_ii]->setColorArray(
1261  _colorsArrays_vertices[unit_ii], osg::Array::BIND_PER_VERTEX);
1262  _geode->addDrawable(_geometries_vertices[unit_ii]);
1263  }
1264 
1265  // [ normals
1266  if(unit_ii == 0) // MUST be done only one time
1267  if(m_Show_Vertex_Normals)
1268  {
1269  _geometries_normals[unit_ii]->setVertexArray(
1270  _vertexArrays_normals[unit_ii]);
1271  _geometries_normals[unit_ii]->setColorArray(
1272  _colorsArrays_normals[unit_ii], osg::Array::BIND_PER_VERTEX);
1273  _geode->addDrawable(_geometries_normals[unit_ii]);
1274  }
1275  // ] normals
1276 
1277  // [ custom_vectors
1278  if(unit_ii == 0) // MUST be done only one time
1279  if(m_Show_CustomVectors_Vertices)
1280  {
1281  _geometries_custom_vectors[unit_ii]->setVertexArray(
1282  _vertexArrays_custom_vectors[unit_ii]);
1283  _geometries_custom_vectors[unit_ii]->setColorArray(
1284  _colorsArrays_custom_vectors[unit_ii], osg::Array::BIND_PER_VERTEX);
1285  _geode->addDrawable(_geometries_custom_vectors[unit_ii]);
1286  }
1287  // ] custom_vectors
1288 
1289  unit_ii++;
1290  } while(unit_ii < _m_mm_size);
1291 
1292  _geode->getOrCreateStateSet()->setMode(
1293  GL_NORMALIZE, osg::StateAttribute::ON); // IMPORTANT : this ensures
1294  // correct lighting (normals)
1295 
1296  if(m_Lighting)
1297  _geode->getOrCreateStateSet()->setMode(GL_LIGHTING,
1298  osg::StateAttribute::ON);
1299  else
1300  _geode->getOrCreateStateSet()->setMode(GL_LIGHTING,
1301  osg::StateAttribute::OFF);
1302 
1303  if(m_SmoothFlat_Shading)
1304  {
1305  osg::ref_ptr< osg::ShadeModel > shadeModel =
1306  new osg::ShadeModel(osg::ShadeModel::SMOOTH);
1307  _geode->getOrCreateStateSet()->setAttribute(shadeModel);
1308  }
1309  else
1310  {
1311  osg::ref_ptr< osg::ShadeModel > shadeModel =
1312  new osg::ShadeModel(osg::ShadeModel::FLAT);
1313  _geode->getOrCreateStateSet()->setAttribute(shadeModel);
1314  }
1315 
1316  osgUtil::Optimizer optimizer; // https://github.com/openscenegraph/OpenSceneGraph/blob/master/include/osgUtil/Optimizer
1317 
1318  if (has_face_color_map)
1319  {
1320  #if OSG_MIN_VERSION_REQUIRED(3, 6, 0)
1321  optimizer.optimize(_geode, osgUtil::Optimizer::BUFFER_OBJECT_SETTINGS /*| osgUtil::Optimizer::MERGE_GEODES*/ /*| osgUtil::Optimizer::MERGE_GEOMETRY*/ /*| osgUtil::Optimizer::MAKE_FAST_GEOMETRY*/);
1322  #else
1323  //optimizer.optimize(_geode, osgUtil::Optimizer::MERGE_GEOMETRY);
1324  #endif
1325  }
1326  else
1327  {
1328  #if OSG_MIN_VERSION_REQUIRED(3, 6, 0)
1329  optimizer.optimize(_geode, osgUtil::Optimizer::BUFFER_OBJECT_SETTINGS /*| osgUtil::Optimizer::MERGE_GEODES*/ | osgUtil::Optimizer::MERGE_GEOMETRY /*| osgUtil::Optimizer::MAKE_FAST_GEOMETRY*/);
1330  #else
1331  optimizer.optimize(_geode, osgUtil::Optimizer::MERGE_GEOMETRY);
1332  #endif
1333  }
1334 }
CameraPosCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *) override
Definition: MeshLoading.inl:28
FEVV::BaseViewer::m_Show_Vertex_Normals
bool m_Show_Vertex_Normals
Definition: BaseViewer.h:189
OSGDebug.hpp
ModelMatrixCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nodeVisitor) override
Definition: MeshLoading.inl:56
CameraPosCallback
Definition: MeshLoading.inl:25
print_osg_img_info
void print_osg_img_info(const osg::Image &osgimg)
Definition: MeshLoading.inl:164
CameraPosCallback::CameraPosCallback
CameraPosCallback(osg::Camera *camera)
Definition: MeshLoading.inl:26
FEVV::BaseViewer::m_SmoothFlat_Shading
bool m_SmoothFlat_Shading
Definition: BaseViewer.h:184
FEVV::BaseViewer::getAdapter
Adapter * getAdapter()
Definition: BaseViewer.h:163
FEVV::Types::Material::ambient_texture_filename
std::string ambient_texture_filename
Definition: Material.h:95
FEVV::Types::Material::emissive_texture_filename
std::string emissive_texture_filename
Definition: Material.h:99
FEVV::BaseViewer
Definition: BaseViewer.h:43
createTexture
osg::ref_ptr< osg::Texture2D > createTexture(const std::string &filename, const FEVV::Types::Material &material)
Definition: MeshLoading.inl:319
ModelMatrixCallback
Definition: MeshLoading.inl:55
FEVV::Types::Material::diffuse_texture_filename
std::string diffuse_texture_filename
Definition: Material.h:97
createDefaultTexture
osg::ref_ptr< osg::Texture2D > createDefaultTexture(uint8_t value=255)
Definition: MeshLoading.inl:139
FEVV::SimpleAdapterVisu
SimpleAdapterVisu is a specialization of QWidget. This class is the widget added to a QMainWindow,...
Definition: SimpleAdapterVisu.h:51
SimpleWindow.h
FEVV::Color::Wisteria
static Color Wisteria(void)
Definition: Color.inl:494
loadMaterialPBR
void loadMaterialPBR(const osg::ref_ptr< osg::Geometry > &geometry, const FEVV::Types::Material &material)
Definition: MeshLoading.inl:412
Material.h
print_cimg_info
void print_cimg_info(const cimg_library::CImg< unsigned char > &cimg)
Definition: MeshLoading.inl:203
MVPMatrixCallback::camera
osg::Camera * camera
Definition: MeshLoading.inl:118
InverseViewMatrixCallback::camera
osg::Camera * camera
Definition: MeshLoading.inl:86
FEVV::BaseViewer::m_Lighting
bool m_Lighting
Definition: BaseViewer.h:183
loadMaterialStandard
void loadMaterialStandard(const osg::ref_ptr< osg::Geometry > &geometry, const FEVV::Types::Material &material)
Definition: MeshLoading.inl:369
MVPMatrixCallback::MVPMatrixCallback
MVPMatrixCallback(osg::Camera *camera)
Definition: MeshLoading.inl:104
FEVV::Types::Image
cimg_library::CImg< unsigned char > Image
Definition: Material.h:41
InverseViewMatrixCallback::InverseViewMatrixCallback
InverseViewMatrixCallback(osg::Camera *camera)
Definition: MeshLoading.inl:78
FEVV::Types::Material::metallic_map_filename
std::string metallic_map_filename
Definition: Material.h:106
CameraTargetCallback::CameraTargetCallback
CameraTargetCallback(osg::Geode *geode)
Definition: MeshLoading.inl:39
FEVV::Types::MaterialType::MATERIAL_TYPE_STANDARD
@ MATERIAL_TYPE_STANDARD
FEVV::get
FEVV::PCLPointCloudPointMap::value_type get(const FEVV::PCLPointCloudPointMap &pm, FEVV::PCLPointCloudPointMap::key_type key)
Specialization of get(point_map, key) for PCLPointCloud.
Definition: Graph_properties_pcl_point_cloud.h:117
InverseViewMatrixCallback
Definition: MeshLoading.inl:77
ProjectionMatrixCallback::camera
osg::Camera * camera
Definition: MeshLoading.inl:99
CameraPosCallback::camera
osg::Camera * camera
Definition: MeshLoading.inl:34
CameraTargetCallback
Definition: MeshLoading.inl:38
FEVV::Types::Material::images
std::map< std::string, std::shared_ptr< Image > > images
Definition: Material.h:113
MVPMatrixCallback
Definition: MeshLoading.inl:103
InverseViewMatrixCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *) override
Definition: MeshLoading.inl:80
FEVV::Types::Material::normal_map_filename
std::string normal_map_filename
Definition: Material.h:101
MVPMatrixCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nodeVisitor) override
Definition: MeshLoading.inl:106
FEVV::vertex_color
@ vertex_color
Definition: properties.h:47
ProjectionMatrixCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *) override
Definition: MeshLoading.inl:93
FEVV::BaseViewer::m_RenderSuperimposedEdges
bool m_RenderSuperimposedEdges
Definition: BaseViewer.h:177
FEVV::BaseViewer::m_RenderSuperimposedVertices
bool m_RenderSuperimposedVertices
Definition: BaseViewer.h:175
ProjectionMatrixCallback::ProjectionMatrixCallback
ProjectionMatrixCallback(osg::Camera *camera)
Definition: MeshLoading.inl:91
FEVV::size_of_faces
boost::graph_traits< MeshT >::faces_size_type size_of_faces(const MeshT &g)
Real current number of faces of the mesh. Generic version.
Definition: Graph_traits_extension.h:80
FEVV::Types::Material
Definition: Material.h:66
FEVV::SimpleViewer::lights
std::vector< osg::ref_ptr< osg::Light > > lights
Definition: SimpleViewer.h:745
CameraTargetCallback::geode
osg::Geode * geode
Definition: MeshLoading.inl:51
ViewMatrixCallback::camera
osg::Camera * camera
Definition: MeshLoading.inl:73
HALFEDGE_TEXCOORDS2D
#define HALFEDGE_TEXCOORDS2D
Definition: Texture.h:20
FEVV::Types::Material::transparency_texture_filename
std::string transparency_texture_filename
Definition: Material.h:100
boost::get
boost::property_map< FEVV::DataStructures::AIF::AIFMesh, boost::vertex_index_t >::const_type get(const boost::vertex_index_t &, const FEVV::DataStructures::AIF::AIFMesh &)
Returns the vertex index property map of the mesh.
Definition: Graph_properties_aif.h:108
FEVV::BaseViewer::m_Show_CustomVectors_Vertices
bool m_Show_CustomVectors_Vertices
Definition: BaseViewer.h:190
FEVV::Types::Material::roughness_map_filename
std::string roughness_map_filename
Definition: Material.h:107
CameraTargetCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *) override
Definition: MeshLoading.inl:41
FEVV::BaseViewer::m_RenderSuperimposedVertices_Big
bool m_RenderSuperimposedVertices_Big
Definition: BaseViewer.h:176
FEVV::Types::Material::specular_texture_filename
std::string specular_texture_filename
Definition: Material.h:98
loadTexturedMesh
osg::ref_ptr< osg::Program > loadTexturedMesh(const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries, const std::vector< osg::ref_ptr< osg::Vec3Array > > &, const std::vector< osg::ref_ptr< osg::Vec3Array > > &, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_tangentsArrays, const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays, bool _useSmoothShading, VertexNormalMap *, VertexTangentMap *_vt_tm, FaceMaterialMap *_m_mm, std::size_t unit_ii)
Definition: MeshLoading.inl:458
ViewMatrixCallback::operator()
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *) override
Definition: MeshLoading.inl:67
VERTEX_TEXCOORDS2D
#define VERTEX_TEXCOORDS2D
Definition: Texture.h:19
recoverBaseDirectory
std::string recoverBaseDirectory()
Definition: MeshLoading.inl:122
loadColoredMesh
osg::ref_ptr< osg::Program > loadColoredMesh(const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries, const std::vector< osg::ref_ptr< osg::Vec3Array > > &, const std::vector< osg::ref_ptr< osg::Vec3Array > > &, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays, VertexNormalMap *, VertexColorMap *_vt_cm, std::size_t unit_ii)
Definition: MeshLoading.inl:568
FEVV::SimpleViewer::internal_loadLegacyMesh
void internal_loadLegacyMesh(osg::Geode *_geode, HalfedgeGraph *_g, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_edges, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_vertices, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_normals, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_custom_vectors, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_edges, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_normals, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_custom_vectors, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_edges, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_edges, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_normals, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_custom_vectors, std::size_t _m_mm_size, int _texture_type, VertexNormalMap *_vt_nm, VertexColorMap *_vt_cm, FaceColorMap *_f_cm, VertexUVMap *_vt_uv_m, HalfedgeUVMap *_het_uv_m, FaceMaterialMap *_m_mm, bool has_face_color_map)
Definition: MeshLoading.inl:1050
FEVV::SimpleViewer::internal_loadShadedMesh
void internal_loadShadedMesh(osg::Geode *_geode, HalfedgeGraph *_g, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_edges, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_vertices, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_normals, const std::vector< osg::ref_ptr< osg::Geometry > > &_geometries_custom_vectors, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_edges, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_normals, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_vertexArrays_custom_vectors, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_edges, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_normalsArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec3Array > > &_tangentsArrays, const std::vector< osg::ref_ptr< osg::Vec2Array > > &_texcoordsArrays, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_edges, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_vertices, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_normals, const std::vector< osg::ref_ptr< osg::Vec4Array > > &_colorsArrays_custom_vectors, std::size_t _m_mm_size, VertexNormalMap *_vt_nm, VertexTangentMap *_vt_tm, VertexColorMap *_vt_cm, FaceColorMap *_f_cm, VertexUVMap *_vt_uv_m, HalfedgeUVMap *_het_uv_m, FaceMaterialMap *_m_mm, bool has_face_color_map)
Definition: MeshLoading.inl:615
ProjectionMatrixCallback
Definition: MeshLoading.inl:90
FEVV::Helpers::ColorConverter
osg::Vec4 ColorConverter(const Color &_color)
Definition: OSGHelpers.h:59
FEVV::make_property_map
PMap_traits< PropertyT, MeshT >::pmap_type make_property_map(PropertyT, const MeshT &m)
Definition: properties.h:630
ViewMatrixCallback::ViewMatrixCallback
ViewMatrixCallback(osg::Camera *camera)
Definition: MeshLoading.inl:65
ViewMatrixCallback
Definition: MeshLoading.inl:64
cimg_to_osgimg
osg::Image * cimg_to_osgimg(const cimg_library::CImg< unsigned char > &cimg)
Definition: MeshLoading.inl:240