MEPP2 Project
FbxFileReader.h
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 Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, 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.
11 #pragma once
12 
13 #include <iostream>
14 #include <vector>
15 #include <cassert>
16 #include <cstdio>
17 #include <string>
18 #include <exception>
19 
20 // FBX SDK
21 //#include <fbxsdk.h>
23 
26 #include "FEVV/Types/Material.h"
27 
28 
29 /*
30  * Doc : http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/
31  */
32 
33 namespace FEVV {
34 namespace IO {
35 
36 
37 using namespace StrUtils;
38 using namespace FileUtils;
39 
40 
44 inline FbxString
45 dbg_get_attr_type_name(FbxNodeAttribute::EType type)
46 {
47  switch(type)
48  {
49  case FbxNodeAttribute::eUnknown:
50  return "unidentified";
51  case FbxNodeAttribute::eNull:
52  return "null";
53  case FbxNodeAttribute::eMarker:
54  return "marker";
55  case FbxNodeAttribute::eSkeleton:
56  return "skeleton";
57  case FbxNodeAttribute::eMesh:
58  return "mesh";
59  case FbxNodeAttribute::eNurbs:
60  return "nurbs";
61  case FbxNodeAttribute::ePatch:
62  return "patch";
63  case FbxNodeAttribute::eCamera:
64  return "camera";
65  case FbxNodeAttribute::eCameraStereo:
66  return "stereo";
67  case FbxNodeAttribute::eCameraSwitcher:
68  return "camera switcher";
69  case FbxNodeAttribute::eLight:
70  return "light";
71  case FbxNodeAttribute::eOpticalReference:
72  return "optical reference";
73  case FbxNodeAttribute::eOpticalMarker:
74  return "marker";
75  case FbxNodeAttribute::eNurbsCurve:
76  return "nurbs curve";
77  case FbxNodeAttribute::eTrimNurbsSurface:
78  return "trim nurbs surface";
79  case FbxNodeAttribute::eBoundary:
80  return "boundary";
81  case FbxNodeAttribute::eNurbsSurface:
82  return "nurbs surface";
83  case FbxNodeAttribute::eShape:
84  return "shape";
85  case FbxNodeAttribute::eLODGroup:
86  return "lodgroup";
87  case FbxNodeAttribute::eSubDiv:
88  return "subdiv";
89  default:
90  return "unknown";
91  }
92 }
93 
97 inline void
98 dbg_print_attribute(FbxNodeAttribute *pAttribute)
99 {
100  if(!pAttribute)
101  return;
102 
103  FbxString typeName = dbg_get_attr_type_name(pAttribute->GetAttributeType());
104  FbxString attrName = pAttribute->GetName();
105 
106  // Note: to retrieve the character array of a FbxString, use its Buffer()
107  // method.
108  std::cout << '\n'
109  << typeName.Buffer() << ' ' << attrName.Buffer() << std::endl;
110 }
111 
115 inline void
116 dbg_print_node(FbxNode *pNode)
117 {
118  const auto nodeName = pNode->GetName();
119  FbxDouble3 translation = pNode->LclTranslation.Get();
120  FbxDouble3 rotation = pNode->LclRotation.Get();
121  FbxDouble3 scaling = pNode->LclScaling.Get();
122 
123  // Print the contents of the node.
124  std::cout << nodeName << ' ' << translation[0] << ' ' << translation[1] << ' '
125  << translation[2] << ' ' << rotation[0] << ' ' << rotation[1] << ' '
126  << rotation[2] << ' ' << scaling[0] << ' ' << scaling[1] << ' '
127  << scaling[2];
128 
129  // Print the node's attributes.
130  for(int i = 0; i < pNode->GetNodeAttributeCount(); ++i)
131  dbg_print_attribute(pNode->GetNodeAttributeByIndex(i));
132 
133  // Recursively print the children.
134  for(int i = 0; i < pNode->GetChildCount(); ++i)
135  dbg_print_node(pNode->GetChild(i));
136 
137  std::cout << std::endl;
138 }
139 
140 inline void
141 dbg_display_infos(const FbxScene &scene)
142 {
143  // Print the nodes of the scene and their attributes recursively.
144  // Note that we are not printing the root node because it should
145  // not contain any attributes.
146  FbxNode *root_node = scene.GetRootNode();
147  if(root_node)
148  {
149  for(int i = 0; i < root_node->GetChildCount(); ++i)
150  dbg_print_node(root_node->GetChild(i));
151  }
152 }
153 
154 
169 template< typename coord_type,
170  typename coordN_type,
171  typename coordT_type,
172  typename coordC_type,
173  typename index_type,
174  typename material_type >
175 void
176 read_fbx_file(const std::string &filePath,
177  std::vector< std::vector< coord_type > > &points_coords,
178  std::vector< std::vector< coordN_type > > &normals_coords,
179  std::vector< std::vector< coordT_type > > &texture_coords,
180  std::vector< std::vector< coordC_type > > & /*vertex_color_coords*/,
181  std::vector< std::vector< index_type > > &face_indices,
182  std::vector< std::vector< index_type > > &texture_face_indices,
183  std::vector< std::vector< index_type > > &normal_face_indices,
184  std::vector< material_type > &materials, // list of materials
185  std::vector< index_type > &face_material) // material of each face
186 {
187  FbxManager *manager = FbxManager::Create();
188 
189  FbxIOSettings *ioSettings = FbxIOSettings::Create(manager, IOSROOT);
190  manager->SetIOSettings(ioSettings);
191 
192  FbxImporter *importer = FbxImporter::Create(manager, "");
193 
194  if(!importer->Initialize(filePath.c_str(), -1, manager->GetIOSettings()))
195  throw std::invalid_argument(
196  {"Reader::read_fbx_file -> Error: couldn't load the given FBX file.\n",
197  importer->GetStatus().GetErrorString()});
198 
199  FbxScene *scene =
200  FbxScene::Create(manager, FileUtils::get_file_name(filePath).c_str());
201 
202  // Importing the contents of the file into the scene
203  importer->Import(scene);
204  importer->Destroy();
205 
206  // RM: may be needed if the mesh is not oriented correctly
207  FbxAxisSystem::OpenGL.ConvertScene(scene);
208 
209  // dbg_display_infos(*scene);
210 
211  //unused auto &settings = scene->GetGlobalSettings();
212 
213  // Recovering geometry
214  for(int meshIndex = 0; meshIndex < scene->GetGeometryCount(); ++meshIndex)
215  {
216  const auto mesh = static_cast< FbxMesh * >(scene->GetGeometry(meshIndex));
217 
218  std::cout << "[FbxFileReader] --- Mesh no." << meshIndex
219  << "'s poly count: " << mesh->GetPolygonCount() << std::endl;
220 
222  // Values //
224 
225  // Recovering positions
226  std::size_t currentVertIndex = points_coords.size();
227  points_coords.resize(currentVertIndex + mesh->GetControlPointsCount(),
228  std::vector< coord_type >(3));
229 
230  for(int vertIndex = 0; vertIndex < mesh->GetControlPointsCount();
231  ++vertIndex, ++currentVertIndex)
232  {
233  const auto &vertPos = mesh->GetControlPointAt(vertIndex);
234 
235  points_coords[currentVertIndex][0] = vertPos[0]; // X position
236  points_coords[currentVertIndex][1] = vertPos[1]; // Y position
237  points_coords[currentVertIndex][2] = vertPos[2]; // Z position
238  }
239 
240  // Recovering normals
241  const auto &meshNormals = mesh->GetElementNormal();
242 
243  if(meshNormals)
244  {
245  std::size_t currentNormIndex = normals_coords.size();
246  normals_coords.resize(currentNormIndex +
247  meshNormals->GetDirectArray().GetCount(),
248  std::vector< coordN_type >(3));
249 
250  for(int normIndex = 0;
251  normIndex < meshNormals->GetDirectArray().GetCount();
252  ++normIndex, ++currentNormIndex)
253  {
254  const auto &normal = meshNormals->GetDirectArray()[normIndex];
255 
256  normals_coords[currentNormIndex][0] = normal[0]; // X
257  normals_coords[currentNormIndex][1] = normal[1]; // Y
258  normals_coords[currentNormIndex][2] = normal[2]; // Z
259  }
260  }
261 
262  // Recovering texture coordinates (UVs)
263  const auto &meshTexcoords = mesh->GetElementUV();
264 
265  if(meshTexcoords)
266  {
267  std::size_t currentTexIndex = texture_coords.size();
268  texture_coords.resize(currentTexIndex +
269  meshTexcoords->GetDirectArray().GetCount(),
270  std::vector< coordT_type >(2));
271 
272  for(int texIndex = 0;
273  texIndex < meshTexcoords->GetDirectArray().GetCount();
274  ++texIndex, ++currentTexIndex)
275  {
276  const auto &texcoords = meshTexcoords->GetDirectArray()[texIndex];
277 
278  texture_coords[currentTexIndex][0] = static_cast<coordT_type>(texcoords[0]); // U
279  texture_coords[currentTexIndex][1] = static_cast<coordT_type>(texcoords[1]); // V
280  }
281  }
282 
284  // Indices //
286 
287  // Fetching positions' indices
288 
289  // We need to make submeshes contiguous in memory; FBX meshes' indices are
290  // starting back from 0 for every mesh We then calculate the base position
291  // index as a stride, to handle contiguous data in memory. Adding it to
292  // indices makes them absolute For example, the first index of the second
293  // mesh will be equal to the amount of entries for the first mesh
294  const std::size_t basePosIndex =
295  points_coords.size() - mesh->GetControlPointsCount();
296  std::size_t currentPosPolyIndex = face_indices.size();
297  face_indices.resize(currentPosPolyIndex + mesh->GetPolygonCount());
298 
299  for(int polyIndex = 0; polyIndex < mesh->GetPolygonCount();
300  ++polyIndex, ++currentPosPolyIndex)
301  {
302  const auto polySize = mesh->GetPolygonSize(polyIndex);
303  face_indices[currentPosPolyIndex].resize(polySize);
304 
305  for(int polyVertIndex = 0; polyVertIndex < polySize; ++polyVertIndex)
306  face_indices[currentPosPolyIndex][polyVertIndex] =
307  basePosIndex + mesh->GetPolygonVertex(polyIndex, polyVertIndex);
308  }
309 
310  // Fetching texture coordinates' indices
311  if(meshTexcoords)
312  {
313  if(meshTexcoords->GetMappingMode() ==
314  FbxLayerElement::EMappingMode::eByControlPoint)
315  {
316  std::cout
317  << "[FbxFileReader] Mapping mesh's texcoords by control point."
318  << std::endl;
319 
320  texture_face_indices.resize(texture_face_indices.size() +
321  mesh->GetPolygonCount());
322 
323  // Getting texcoords for each vertex, since the mapping mode of
324  // texcoords element is by control point
325  for(std::size_t faceIndex =
326  face_indices.size() - mesh->GetPolygonCount();
327  faceIndex < face_indices.size();
328  ++faceIndex)
329  {
330  texture_face_indices[faceIndex].resize(
331  face_indices[faceIndex].size());
332 
333  for(size_t vertIndex = 0; vertIndex < face_indices[faceIndex].size();
334  ++vertIndex)
335  {
336  index_type texIndex{};
337 
338  if(meshTexcoords->GetReferenceMode() ==
339  FbxGeometryElement::eDirect) // Texcoords index is the same as
340  // vertex index
341  texIndex = face_indices[faceIndex][vertIndex];
342  else if(meshTexcoords->GetReferenceMode() ==
343  FbxGeometryElement::eIndexToDirect) // Get texcoords index
344  // by polygon vertex
345  texIndex = meshTexcoords->GetIndexArray().GetAt(
346  static_cast< int >(face_indices[faceIndex][vertIndex]));
347 
348  texture_face_indices[faceIndex][vertIndex] = texIndex;
349  }
350  }
351  }
352  else if(meshTexcoords->GetMappingMode() ==
353  FbxLayerElement::EMappingMode::eByPolygonVertex)
354  {
355  std::cout
356  << "[FbxFileReader] Mapping mesh's texcoords by face vertices."
357  << std::endl;
358 
359  const std::size_t baseTexIndex =
360  texture_coords.size() - meshTexcoords->GetDirectArray().GetCount();
361  std::size_t globalTexIndex = texture_face_indices.size();
362  texture_face_indices.resize(globalTexIndex + mesh->GetPolygonCount());
363  int currentTexPolyIndex = 0;
364 
365  // Getting texcoords of each polygon, since the mapping mode of
366  // texcoords element is by polygon-vertex
367  for(int polyIndex = 0; polyIndex < mesh->GetPolygonCount();
368  ++polyIndex, ++globalTexIndex)
369  {
370  texture_face_indices[globalTexIndex].resize(
371  mesh->GetPolygonSize(polyIndex));
372 
373  // Retrieve each vertex of current polygon
374  for(int polyVertIndex = 0;
375  polyVertIndex < mesh->GetPolygonSize(polyIndex);
376  ++polyVertIndex, ++currentTexPolyIndex)
377  {
378  index_type texIndex{};
379 
380  if(meshTexcoords->GetReferenceMode() == FbxGeometryElement::eDirect)
381  texIndex = currentTexPolyIndex;
382  else if(meshTexcoords->GetReferenceMode() ==
383  FbxGeometryElement::eIndexToDirect)
384  texIndex =
385  meshTexcoords->GetIndexArray().GetAt(currentTexPolyIndex);
386 
387  texture_face_indices[globalTexIndex][polyVertIndex] =
388  baseTexIndex + texIndex;
389  }
390  }
391  }
392  else
393  {
394  std::cerr
395  << "[FbxFileReader] Couldn't handle mesh's texcoords' mapping mode."
396  << std::endl;
397  }
398  }
399 
400  if(meshNormals)
401  {
402  if(meshNormals->GetMappingMode() ==
403  FbxLayerElement::EMappingMode::eByControlPoint)
404  {
405  std::cout << "[FbxFileReader] Mapping mesh's normals by control point."
406  << std::endl;
407 
408  normal_face_indices.resize(normal_face_indices.size() +
409  mesh->GetPolygonCount());
410 
411  // Getting normals for each vertex, since the mapping mode of normal
412  // element is by control point
413  for(std::size_t faceIndex =
414  face_indices.size() - mesh->GetPolygonCount();
415  faceIndex < face_indices.size();
416  ++faceIndex)
417  {
418  normal_face_indices[faceIndex].resize(face_indices[faceIndex].size());
419 
420  for(size_t vertIndex = 0; vertIndex < face_indices[faceIndex].size();
421  ++vertIndex)
422  {
423  index_type normIndex{};
424 
425  if(meshNormals->GetReferenceMode() ==
426  FbxGeometryElement::eDirect) // Normal index is the same as
427  // vertex index
428  normIndex = face_indices[faceIndex][vertIndex];
429  else if(meshNormals->GetReferenceMode() ==
430  FbxGeometryElement::eIndexToDirect) // Get normal index by
431  // polygon vertex
432  normIndex = meshNormals->GetIndexArray().GetAt(
433  static_cast< int >(face_indices[faceIndex][vertIndex]));
434 
435  normal_face_indices[faceIndex][vertIndex] = normIndex;
436  }
437  }
438  }
439  else if(meshNormals->GetMappingMode() ==
440  FbxLayerElement::EMappingMode::eByPolygonVertex)
441  {
442  std::cout << "[FbxFileReader] Mapping mesh's normals by face vertices."
443  << std::endl;
444 
445  const std::size_t baseNormIndex =
446  normals_coords.size() - meshNormals->GetDirectArray().GetCount();
447  std::size_t globalNormIndex = normal_face_indices.size();
448  normal_face_indices.resize(globalNormIndex + mesh->GetPolygonCount());
449  int currentNormPolyIndex = 0;
450 
451  // Getting normals of each polygon, since the mapping mode of normal
452  // element is by polygon-vertex
453  for(int polyIndex = 0; polyIndex < mesh->GetPolygonCount();
454  ++polyIndex, ++globalNormIndex)
455  {
456  normal_face_indices[globalNormIndex].resize(
457  mesh->GetPolygonSize(polyIndex));
458 
459  // Retrieve each vertex of current polygon
460  for(int polyVertIndex = 0;
461  polyVertIndex < mesh->GetPolygonSize(polyIndex);
462  ++polyVertIndex, ++currentNormPolyIndex)
463  {
464  index_type normIndex{};
465 
466  if(meshNormals->GetReferenceMode() == FbxGeometryElement::eDirect)
467  normIndex = currentNormPolyIndex;
468  else if(meshNormals->GetReferenceMode() ==
469  FbxGeometryElement::eIndexToDirect)
470  normIndex =
471  meshNormals->GetIndexArray().GetAt(currentNormPolyIndex);
472 
473  normal_face_indices[globalNormIndex][polyVertIndex] =
474  baseNormIndex + normIndex;
475  }
476  }
477  }
478  else
479  {
480  std::cerr
481  << "[FbxFileReader] Couldn't handle mesh's normals' mapping mode."
482  << std::endl;
483  }
484  }
485 
486  const auto &meshMaterial = mesh->GetElementMaterial();
487  if(meshMaterial)
488  {
489  if(meshMaterial->GetMappingMode() ==
490  FbxLayerElement::EMappingMode::eByPolygon)
491  {
492  face_material.resize(mesh->GetPolygonCount());
493 
494  for(int polyIndex = 0; polyIndex < mesh->GetPolygonCount(); ++polyIndex)
495  face_material[polyIndex] = meshMaterial->GetIndexArray()[polyIndex];
496  }
497  else if(meshMaterial->GetMappingMode() ==
498  FbxLayerElement::EMappingMode::eAllSame)
499  {
500  const std::size_t prevFaceMatSize = face_material.size();
501 
502  face_material.resize(prevFaceMatSize + mesh->GetPolygonCount());
503  // REALLY bad hack here: without this std::min, that works for meshes
504  // with the same amount of materials and meshes Clamping here
505  // temporarily prevents segfaulting, but obviously isn't a long-term
506  // solution
507  std::fill(face_material.begin() + prevFaceMatSize,
508  face_material.end(),
509  std::min(meshIndex, scene->GetMaterialCount() - 1));
510  }
511  }
512  }
513 
514  // Recovering materials
515  materials.resize(scene->GetMaterialCount());
516 
517  for(int matIndex = 0; matIndex < scene->GetMaterialCount(); ++matIndex)
518  {
519  const FbxSurfaceMaterial *material = scene->GetMaterial(matIndex);
520 
521  materials[matIndex].name = material->GetName();
522 
523  // Recovering properties from the material
524 
525  const FbxPropertyT< FbxDouble3 > &ambient =
526  material->FindProperty(FbxSurfaceMaterial::sAmbient);
527  if(ambient.IsValid())
528  {
529  materials[matIndex].ambient_red_component = ambient.Get()[0];
530  materials[matIndex].ambient_green_component = ambient.Get()[1];
531  materials[matIndex].ambient_blue_component = ambient.Get()[2];
532  }
533 
534  const FbxPropertyT< FbxDouble3 > &diffuse =
535  material->FindProperty(FbxSurfaceMaterial::sDiffuse);
536  if(diffuse.IsValid())
537  {
538  materials[matIndex].diffuse_red_component = diffuse.Get()[0];
539  materials[matIndex].diffuse_green_component = diffuse.Get()[1];
540  materials[matIndex].diffuse_blue_component = diffuse.Get()[2];
541  }
542 
543  const FbxPropertyT< FbxDouble3 > &specular =
544  material->FindProperty(FbxSurfaceMaterial::sSpecular);
545  if(specular.IsValid())
546  {
547  materials[matIndex].specular_red_component = specular.Get()[0];
548  materials[matIndex].specular_green_component = specular.Get()[1];
549  materials[matIndex].specular_blue_component = specular.Get()[2];
550  }
551 
552  const FbxPropertyT< FbxDouble3 > &emissive =
553  material->FindProperty(FbxSurfaceMaterial::sEmissive);
554  if(emissive.IsValid())
555  {
556  materials[matIndex].emissive_red_component = emissive.Get()[0];
557  materials[matIndex].emissive_green_component = emissive.Get()[1];
558  materials[matIndex].emissive_blue_component = emissive.Get()[2];
559  }
560 
561  const FbxPropertyT< FbxDouble > &transparency =
562  material->FindProperty(FbxSurfaceMaterial::sTransparencyFactor);
563  if(transparency.IsValid())
564  materials[matIndex].transparency = transparency.Get();
565 
566  // Recovering textures associated to the material
567  const auto parent_directory = get_parent_directory(filePath);
568 
569  const auto ambientTexture = static_cast< FbxFileTexture * >(
570  ambient.GetSrcObject(FbxCriteria::ObjectType(FbxFileTexture::ClassId)));
571  if(ambientTexture)
572  {
573  materials[matIndex].ambient_texture_filename =
574  ambientTexture->GetRelativeFileName();
575  materials[matIndex].ambient_texture_filename.insert(
576  0, parent_directory + "/");
577  }
578 
579  const auto diffuseTexture = static_cast< FbxFileTexture * >(
580  diffuse.GetSrcObject(FbxCriteria::ObjectType(FbxFileTexture::ClassId)));
581  if(diffuseTexture)
582  {
583  materials[matIndex].diffuse_texture_filename =
584  diffuseTexture->GetRelativeFileName();
585  materials[matIndex].diffuse_texture_filename.insert(
586  0, parent_directory + "/");
587  }
588 
589  const auto specularTexture =
590  static_cast< FbxFileTexture * >(specular.GetSrcObject(
591  FbxCriteria::ObjectType(FbxFileTexture::ClassId)));
592  if(specularTexture)
593  {
594  materials[matIndex].specular_texture_filename =
595  specularTexture->GetRelativeFileName();
596  materials[matIndex].specular_texture_filename.insert(
597  0, parent_directory + "/");
598  }
599 
600  const auto emissiveTexture =
601  static_cast< FbxFileTexture * >(emissive.GetSrcObject(
602  FbxCriteria::ObjectType(FbxFileTexture::ClassId)));
603  if(emissiveTexture)
604  {
605  materials[matIndex].emissive_texture_filename =
606  emissiveTexture->GetRelativeFileName();
607  materials[matIndex].emissive_texture_filename.insert(
608  0, parent_directory + "/");
609  }
610 
611  const auto normalMapProp =
612  material->FindProperty(FbxSurfaceMaterial::sNormalMap);
613  if(normalMapProp.IsValid())
614  {
615  const auto normalMap =
616  static_cast< FbxFileTexture * >(normalMapProp.GetSrcObject(
617  FbxCriteria::ObjectType(FbxFileTexture::ClassId)));
618  if(normalMap)
619  {
620  materials[matIndex].normal_map_filename =
621  normalMap->GetRelativeFileName();
622  materials[matIndex].normal_map_filename.insert(0,
623  parent_directory + "/");
624 
625  materials[matIndex].has_normal_map = true;
626  }
627  }
628  }
629 
630  manager->Destroy(); // Finally destroying the FbxManager now that we've
631  // imported our scene
632 }
633 
634 } // namespace IO
635 } // namespace FEVV
636 
637 #undef isnan // fix issue with std::isnan due to fbxmath.h
FEVV::IO::read_fbx_file
void read_fbx_file(const std::string &filePath, std::vector< std::vector< coord_type > > &points_coords, std::vector< std::vector< coordN_type > > &normals_coords, std::vector< std::vector< coordT_type > > &texture_coords, std::vector< std::vector< coordC_type > > &, std::vector< std::vector< index_type > > &face_indices, std::vector< std::vector< index_type > > &texture_face_indices, std::vector< std::vector< index_type > > &normal_face_indices, std::vector< material_type > &materials, std::vector< index_type > &face_material)
Read the FBX file and load its data into given parameters.
Definition: FbxFileReader.h:176
Material.h
FEVV::IO::dbg_print_attribute
void dbg_print_attribute(FbxNodeAttribute *pAttribute)
Definition: FbxFileReader.h:98
FEVV::IO::dbg_get_attr_type_name
FbxString dbg_get_attr_type_name(FbxNodeAttribute::EType type)
Definition: FbxFileReader.h:45
FEVV::FileUtils::get_file_name
std::string get_file_name(const std::string &file_name)
Definition: FileUtilities.hpp:128
FEVV
Interfaces for plugins These interfaces will be used for different plugins.
Definition: Assert.h:16
FbxSdkNoWarning.h
FEVV::face_material
@ face_material
Definition: properties.h:85
FEVV::IO::dbg_print_node
void dbg_print_node(FbxNode *pNode)
Definition: FbxFileReader.h:116
StringUtilities.hpp
FEVV::IO::dbg_display_infos
void dbg_display_infos(const FbxScene &scene)
Definition: FbxFileReader.h:141
FEVV::FileUtils::get_parent_directory
std::string get_parent_directory(const std::string &file_name)
Definition: FileUtilities.hpp:191
FileUtilities.hpp