mesh_loader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "mesh_loader.h"
32 
33 #include <boost/filesystem.hpp>
34 
36 
37 #include <OgreMeshManager.h>
38 #include <OgreTextureManager.h>
39 #include <OgreMaterialManager.h>
40 #include <OgreTexture.h>
41 #include <OgrePass.h>
42 #include <OgreTechnique.h>
43 #include <OgreMaterial.h>
44 #include <OgreTextureUnitState.h>
45 #include <OgreMeshSerializer.h>
46 #include <OgreSubMesh.h>
47 #include <OgreHardwareBufferManager.h>
48 #include <OgreSharedPtr.h>
49 #include <OgreTechnique.h>
50 
51 #include <tinyxml.h>
52 
53 
54 #include <ros/assert.h>
55 
56 #if defined(ASSIMP_UNIFIED_HEADER_NAMES)
57 #include <assimp/Importer.hpp>
58 #include <assimp/scene.h>
59 #include <assimp/postprocess.h>
60 #include <assimp/IOStream.hpp>
61 #include <assimp/IOSystem.hpp>
62 #else
63 #include <assimp/assimp.hpp>
64 #include <assimp/aiScene.h>
65 #include <assimp/aiPostProcess.h>
66 #include <assimp/IOStream.h>
67 #include <assimp/IOSystem.h>
68 #endif
69 
70 namespace fs = boost::filesystem;
71 
72 namespace rviz
73 {
74 
75 class ResourceIOStream : public Assimp::IOStream
76 {
77 public:
79  : res_(res)
80  , pos_(res.data.get())
81  {}
82 
84  {}
85 
86  size_t Read(void* buffer, size_t size, size_t count)
87  {
88  size_t to_read = size * count;
89  if (pos_ + to_read > res_.data.get() + res_.size)
90  {
91  to_read = res_.size - (pos_ - res_.data.get());
92  }
93 
94  memcpy(buffer, pos_, to_read);
95  pos_ += to_read;
96 
97  return to_read;
98  }
99 
100  size_t Write( const void* buffer, size_t size, size_t count) { ROS_BREAK(); return 0; }
101 
102  aiReturn Seek( size_t offset, aiOrigin origin)
103  {
104  uint8_t* new_pos = 0;
105  switch (origin)
106  {
107  case aiOrigin_SET:
108  new_pos = res_.data.get() + offset;
109  break;
110  case aiOrigin_CUR:
111  new_pos = pos_ + offset; // TODO is this right? can offset really not be negative
112  break;
113  case aiOrigin_END:
114  new_pos = res_.data.get() + res_.size - offset; // TODO is this right?
115  break;
116  default:
117  ROS_BREAK();
118  }
119 
120  if (new_pos < res_.data.get() || new_pos > res_.data.get() + res_.size)
121  {
122  return aiReturn_FAILURE;
123  }
124 
125  pos_ = new_pos;
126  return aiReturn_SUCCESS;
127  }
128 
129  size_t Tell() const
130  {
131  return pos_ - res_.data.get();
132  }
133 
134  size_t FileSize() const
135  {
136  return res_.size;
137  }
138 
139  void Flush() {}
140 
141 private:
143  uint8_t* pos_;
144 };
145 
146 class ResourceIOSystem : public Assimp::IOSystem
147 {
148 public:
150  {
151  }
152 
154  {
155  }
156 
157  // Check whether a specific file exists
158  bool Exists(const char* file) const
159  {
160  // Ugly -- two retrievals where there should be one (Exists + Open)
161  // resource_retriever needs a way of checking for existence
162  // TODO: cache this
164  try
165  {
166  res = retriever_.get(file);
167  }
169  {
170  return false;
171  }
172 
173  return true;
174  }
175 
176  // Get the path delimiter character we'd like to see
177  char getOsSeparator() const
178  {
179  return '/';
180  }
181 
182  // ... and finally a method to open a custom stream
183  Assimp::IOStream* Open(const char* file, const char* mode = "rb")
184  {
185  ROS_ASSERT(mode == std::string("r") || mode == std::string("rb"));
186 
187  // Ugly -- two retrievals where there should be one (Exists + Open)
188  // resource_retriever needs a way of checking for existence
190  try
191  {
192  res = retriever_.get(file);
193  }
195  {
196  return 0;
197  }
198 
199  return new ResourceIOStream(res);
200  }
201 
202  void Close(Assimp::IOStream* stream);
203 
204 private:
206 };
207 
208 void ResourceIOSystem::Close(Assimp::IOStream* stream)
209 {
210  delete stream;
211 }
212 
213 // Mostly stolen from gazebo
218 void buildMesh( const aiScene* scene, const aiNode* node,
219  const Ogre::MeshPtr& mesh,
220  Ogre::AxisAlignedBox& aabb, float& radius, const float scale,
221  std::vector<Ogre::MaterialPtr>& material_table )
222 {
223  if (!node)
224  {
225  return;
226  }
227 
228  aiMatrix4x4 transform = node->mTransformation;
229  aiNode *pnode = node->mParent;
230  while (pnode)
231  {
232  // Don't convert to y-up orientation, which is what the root node in
233  // Assimp does
234  if (pnode->mParent != NULL)
235  transform = pnode->mTransformation * transform;
236  pnode = pnode->mParent;
237  }
238 
239  aiMatrix3x3 rotation(transform);
240  aiMatrix3x3 inverse_transpose_rotation(rotation);
241  inverse_transpose_rotation.Inverse();
242  inverse_transpose_rotation.Transpose();
243 
244  for (uint32_t i = 0; i < node->mNumMeshes; i++)
245  {
246  aiMesh* input_mesh = scene->mMeshes[node->mMeshes[i]];
247 
248  Ogre::SubMesh* submesh = mesh->createSubMesh();
249  submesh->useSharedVertices = false;
250  submesh->vertexData = new Ogre::VertexData();
251  Ogre::VertexData* vertex_data = submesh->vertexData;
252  Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration;
253 
254  size_t offset = 0;
255  // positions
256  vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
257  offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
258 
259  // normals
260  if (input_mesh->HasNormals())
261  {
262  vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
263  offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
264  }
265 
266  // texture coordinates (only support 1 for now)
267  if (input_mesh->HasTextureCoords(0))
268  {
269  vertex_decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
270  offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
271  }
272 
273  // todo vertex colors
274 
275  // allocate the vertex buffer
276  vertex_data->vertexCount = input_mesh->mNumVertices;
277  Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertex_decl->getVertexSize(0),
278  vertex_data->vertexCount,
279  Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
280  false);
281 
282  vertex_data->vertexBufferBinding->setBinding(0, vbuf);
283  float* vertices = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
284 
285  // Add the vertices
286  for (uint32_t j = 0; j < input_mesh->mNumVertices; j++)
287  {
288  aiVector3D p = input_mesh->mVertices[j];
289  p *= transform;
290  p *= scale;
291  *vertices++ = p.x;
292  *vertices++ = p.y;
293  *vertices++ = p.z;
294 
295  Ogre::Vector3 v(p.x, p.y, p.z);
296  aabb.merge(v);
297  float dist = v.length();
298  if (dist > radius)
299  {
300  radius = dist;
301  }
302 
303  if (input_mesh->HasNormals())
304  {
305  aiVector3D n = inverse_transpose_rotation * input_mesh->mNormals[j];
306  n.Normalize();
307  *vertices++ = n.x;
308  *vertices++ = n.y;
309  *vertices++ = n.z;
310  }
311 
312  if (input_mesh->HasTextureCoords(0))
313  {
314  *vertices++ = input_mesh->mTextureCoords[0][j].x;
315  *vertices++ = input_mesh->mTextureCoords[0][j].y;
316  }
317  }
318 
319  // calculate index count
320  submesh->indexData->indexCount = 0;
321  for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
322  {
323  aiFace& face = input_mesh->mFaces[j];
324  submesh->indexData->indexCount += face.mNumIndices;
325  }
326 
327  // If we have less than 65536 (2^16) vertices, we can use a 16-bit index buffer.
328  if( vertex_data->vertexCount < (1<<16) )
329  {
330  // allocate index buffer
331  submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
332  Ogre::HardwareIndexBuffer::IT_16BIT,
333  submesh->indexData->indexCount,
334  Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
335  false);
336 
337  Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
338  uint16_t* indices = static_cast<uint16_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
339 
340  // add the indices
341  for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
342  {
343  aiFace& face = input_mesh->mFaces[j];
344  for (uint32_t k = 0; k < face.mNumIndices; ++k)
345  {
346  *indices++ = face.mIndices[k];
347  }
348  }
349 
350  ibuf->unlock();
351  }
352  else
353  {
354  // Else we have more than 65536 (2^16) vertices, so we must
355  // use a 32-bit index buffer (or subdivide the mesh, which
356  // I'm too impatient to do right now)
357 
358  // allocate index buffer
359  submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
360  Ogre::HardwareIndexBuffer::IT_32BIT,
361  submesh->indexData->indexCount,
362  Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
363  false);
364 
365  Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
366  uint32_t* indices = static_cast<uint32_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
367 
368  // add the indices
369  for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
370  {
371  aiFace& face = input_mesh->mFaces[j];
372  for (uint32_t k = 0; k < face.mNumIndices; ++k)
373  {
374  *indices++ = face.mIndices[k];
375  }
376  }
377 
378  ibuf->unlock();
379  }
380  vbuf->unlock();
381 
382  submesh->setMaterialName(material_table[input_mesh->mMaterialIndex]->getName());
383  }
384 
385  for (uint32_t i=0; i < node->mNumChildren; ++i)
386  {
387  buildMesh(scene, node->mChildren[i], mesh, aabb, radius, scale, material_table);
388  }
389 }
390 
391 void loadTexture(const std::string& resource_path)
392 {
393  if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path))
394  {
397  try
398  {
399  res = retriever.get(resource_path);
400  }
402  {
403  ROS_ERROR("%s", e.what());
404  }
405 
406  if (res.size != 0)
407  {
408  Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
409  Ogre::Image image;
410  std::string extension = fs::extension(fs::path(resource_path));
411 
412  if (extension[0] == '.')
413  {
414  extension = extension.substr(1, extension.size() - 1);
415  }
416 
417  try
418  {
419  image.load(stream, extension);
420  Ogre::TextureManager::getSingleton().loadImage(resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image);
421  }
422  catch (Ogre::Exception& e)
423  {
424  ROS_ERROR("Could not load texture [%s]: %s", resource_path.c_str(), e.what());
425  }
426  }
427  }
428 }
429 
430 // Mostly cribbed from gazebo
437 void loadMaterials(const std::string& resource_path,
438  const aiScene* scene,
439  std::vector<Ogre::MaterialPtr>& material_table_out )
440 {
441  for (uint32_t i = 0; i < scene->mNumMaterials; i++)
442  {
443  std::stringstream ss;
444  ss << resource_path << "Material" << i;
445  Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME, true);
446  material_table_out.push_back(mat);
447 
448  Ogre::Technique* tech = mat->getTechnique(0);
449  Ogre::Pass* pass = tech->getPass(0);
450 
451  aiMaterial *amat = scene->mMaterials[i];
452 
453  Ogre::ColourValue diffuse(1.0, 1.0, 1.0, 1.0);
454  Ogre::ColourValue specular(1.0, 1.0, 1.0, 1.0);
455  Ogre::ColourValue ambient(0, 0, 0, 1.0);
456 
457  for (uint32_t j=0; j < amat->mNumProperties; j++)
458  {
459  aiMaterialProperty *prop = amat->mProperties[j];
460  std::string propKey = prop->mKey.data;
461 
462  if (propKey == "$tex.file")
463  {
464  aiString texName;
465  aiTextureMapping mapping;
466  uint32_t uvIndex;
467  amat->GetTexture(aiTextureType_DIFFUSE,0, &texName, &mapping, &uvIndex);
468 
469  // Assume textures are in paths relative to the mesh
470  std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + texName.data;
471  loadTexture(texture_path);
472  Ogre::TextureUnitState* tu = pass->createTextureUnitState();
473  tu->setTextureName(texture_path);
474  }
475  else if (propKey == "$clr.diffuse")
476  {
477  aiColor3D clr;
478  amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr);
479  diffuse = Ogre::ColourValue(clr.r, clr.g, clr.b);
480  }
481  else if (propKey == "$clr.ambient")
482  {
483  aiColor3D clr;
484  amat->Get(AI_MATKEY_COLOR_AMBIENT, clr);
485  ambient = Ogre::ColourValue(clr.r, clr.g, clr.b);
486  }
487  else if (propKey == "$clr.specular")
488  {
489  aiColor3D clr;
490  amat->Get(AI_MATKEY_COLOR_SPECULAR, clr);
491  specular = Ogre::ColourValue(clr.r, clr.g, clr.b);
492  }
493  else if (propKey == "$clr.emissive")
494  {
495  aiColor3D clr;
496  amat->Get(AI_MATKEY_COLOR_EMISSIVE, clr);
497  mat->setSelfIllumination(clr.r, clr.g, clr.b);
498  }
499  else if (propKey == "$clr.opacity")
500  {
501  float o;
502  amat->Get(AI_MATKEY_OPACITY, o);
503  diffuse.a = o;
504  }
505  else if (propKey == "$mat.shininess")
506  {
507  float s;
508  amat->Get(AI_MATKEY_SHININESS, s);
509  mat->setShininess(s);
510  }
511  else if (propKey == "$mat.shadingm")
512  {
513  int model;
514  amat->Get(AI_MATKEY_SHADING_MODEL, model);
515  switch(model)
516  {
517  case aiShadingMode_Flat:
518  mat->setShadingMode(Ogre::SO_FLAT);
519  break;
520  case aiShadingMode_Phong:
521  mat->setShadingMode(Ogre::SO_PHONG);
522  break;
523  case aiShadingMode_Gouraud:
524  default:
525  mat->setShadingMode(Ogre::SO_GOURAUD);
526  break;
527  }
528  }
529  }
530 
531  int mode = aiBlendMode_Default;
532  amat->Get(AI_MATKEY_BLEND_FUNC, mode);
533  switch(mode)
534  {
535  case aiBlendMode_Additive:
536  mat->setSceneBlending(Ogre::SBT_ADD);
537  break;
538  case aiBlendMode_Default:
539  default:
540  {
541  if (diffuse.a < 0.99)
542  {
543  pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
544  }
545  else
546  {
547  pass->setSceneBlending(Ogre::SBT_REPLACE);
548  }
549  }
550  break;
551  }
552 
553  mat->setAmbient(ambient * 0.5);
554  mat->setDiffuse(diffuse);
555  specular.a = diffuse.a;
556  mat->setSpecular(specular);
557  }
558 }
559 
560 
561 /*@brief - Get the scaling from units used in this mesh file to meters.
562 
563  This function applies only to Collada files. It is necessary because
564  ASSIMP does not currently expose an api to retrieve the scaling factor.
565 
566  @Param[in] resource_path - The url of a resource containing a mesh.
567 
568  @Returns The scaling factor that converts the mesh to meters. Returns 1.0
569  for meshes which do not explicitly encode such a scaling.
570 
571 */
572 
573 float getMeshUnitRescale(const std::string& resource_path)
574 {
575  static std::map<std::string, float> rescale_cache;
576 
577 
578 
579  // Try to read unit to meter conversion ratio from mesh. Only valid in Collada XML formats.
580  TiXmlDocument xmlDoc;
581  float unit_scale(1.0);
584  try
585  {
586  res = retriever.get(resource_path);
587  }
589  {
590  ROS_ERROR("%s", e.what());
591  return unit_scale;
592  }
593 
594  if (res.size == 0)
595  {
596  return unit_scale;
597  }
598 
599 
600  // Use the resource retriever to get the data.
601  const char * data = reinterpret_cast<const char * > (res.data.get());
602  xmlDoc.Parse(data);
603 
604  // Find the appropriate element if it exists
605  if(!xmlDoc.Error())
606  {
607  TiXmlElement * colladaXml = xmlDoc.FirstChildElement("COLLADA");
608  if(colladaXml)
609  {
610  TiXmlElement *assetXml = colladaXml->FirstChildElement("asset");
611  if(assetXml)
612  {
613  TiXmlElement *unitXml = assetXml->FirstChildElement("unit");
614  if (unitXml && unitXml->Attribute("meter"))
615  {
616  // Failing to convert leaves unit_scale as the default.
617  if(unitXml->QueryFloatAttribute("meter", &unit_scale) != 0)
618  ROS_WARN_STREAM("getMeshUnitRescale::Failed to convert unit element meter attribute to determine scaling. unit element: "
619  << *unitXml);
620  }
621  }
622  }
623  }
624  return unit_scale;
625 }
626 
627 
628 
629 Ogre::MeshPtr meshFromAssimpScene(const std::string& name, const aiScene* scene)
630 {
631  if (!scene->HasMeshes())
632  {
633  ROS_ERROR("No meshes found in file [%s]", name.c_str());
634  return Ogre::MeshPtr();
635  }
636 
637  std::vector<Ogre::MaterialPtr> material_table;
638  loadMaterials(name, scene, material_table);
639 
640  Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(name, ROS_PACKAGE_NAME);
641 
642  Ogre::AxisAlignedBox aabb(Ogre::AxisAlignedBox::EXTENT_NULL);
643  float radius = 0.0f;
644  float scale = getMeshUnitRescale(name);
645  buildMesh(scene, scene->mRootNode, mesh, aabb, radius, scale, material_table);
646 
647  mesh->_setBounds(aabb);
648  mesh->_setBoundingSphereRadius(radius);
649  mesh->buildEdgeList();
650 
651  mesh->load();
652 
653  return mesh;
654 }
655 
656 Ogre::MeshPtr loadMeshFromResource(const std::string& resource_path)
657 {
658  if (Ogre::MeshManager::getSingleton().resourceExists(resource_path))
659  {
660  return Ogre::MeshManager::getSingleton().getByName(resource_path);
661  }
662  else
663  {
664  fs::path model_path(resource_path);
665 #if BOOST_FILESYSTEM_VERSION == 3
666  std::string ext = model_path.extension().string();
667 #else
668  std::string ext = model_path.extension();
669 #endif
670  if (ext == ".mesh" || ext == ".MESH")
671  {
674  try
675  {
676  res = retriever.get(resource_path);
677  }
679  {
680  ROS_ERROR("%s", e.what());
681  return Ogre::MeshPtr();
682  }
683 
684  if (res.size == 0)
685  {
686  return Ogre::MeshPtr();
687  }
688 
689  Ogre::MeshSerializer ser;
690  Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
691  Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(resource_path, "rviz");
692  ser.importMesh(stream, mesh.get());
693 
694  return mesh;
695  }
696  else if (ext == ".stl" || ext == ".STL" || ext == ".stlb" || ext == ".STLB")
697  {
700  try
701  {
702  res = retriever.get(resource_path);
703  }
705  {
706  ROS_ERROR("%s", e.what());
707  return Ogre::MeshPtr();
708  }
709 
710  if (res.size == 0)
711  {
712  return Ogre::MeshPtr();
713  }
714 
715  ogre_tools::STLLoader loader;
716  if (!loader.load(res.data.get(), res.size, resource_path))
717  {
718  ROS_ERROR("Failed to load file [%s]", resource_path.c_str());
719  return Ogre::MeshPtr();
720  }
721 
722  return loader.toMesh(resource_path);
723  }
724  else
725  {
726  Assimp::Importer importer;
727  importer.SetIOHandler(new ResourceIOSystem());
728  const aiScene* scene = importer.ReadFile(resource_path, aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs);
729  if (!scene)
730  {
731  ROS_ERROR("Could not load resource [%s]: %s", resource_path.c_str(), importer.GetErrorString());
732  return Ogre::MeshPtr();
733  }
734 
735  return meshFromAssimpScene(resource_path, scene);
736  }
737  }
738 
739  return Ogre::MeshPtr();
740 }
741 
742 }
#define NULL
Definition: global.h:37
XmlRpcServer s
ResourceIOStream(const resource_retriever::MemoryResource &res)
Definition: mesh_loader.cpp:78
bool load(const std::string &path)
Definition: stl_loader.cpp:48
float getMeshUnitRescale(const std::string &resource_path)
Ogre::MeshPtr loadMeshFromResource(const std::string &resource_path)
def get(url)
size_t Write(const void *buffer, size_t size, size_t count)
void loadTexture(const std::string &resource_path)
void loadMaterials(const std::string &resource_path, const aiScene *scene, std::vector< Ogre::MaterialPtr > &material_table_out)
Load all materials needed by the given scene.
boost::shared_array< uint8_t > data
resource_retriever::Retriever retriever_
size_t FileSize() const
#define ROS_WARN_STREAM(args)
MemoryResource get(const std::string &url)
void buildMesh(const aiScene *scene, const aiNode *node, const Ogre::MeshPtr &mesh, Ogre::AxisAlignedBox &aabb, float &radius, const float scale, std::vector< Ogre::MaterialPtr > &material_table)
Recursive mesh-building function.
size_t Read(void *buffer, size_t size, size_t count)
Definition: mesh_loader.cpp:86
void Close(Assimp::IOStream *stream)
Ogre::MeshPtr toMesh(const std::string &name)
Definition: stl_loader.cpp:233
char getOsSeparator() const
size_t Tell() const
bool Exists(const char *file) const
#define ROS_ASSERT(cond)
#define ROS_BREAK()
resource_retriever::MemoryResource res_
#define ROS_ERROR(...)
Assimp::IOStream * Open(const char *file, const char *mode="rb")
Ogre::MeshPtr meshFromAssimpScene(const std::string &name, const aiScene *scene)
aiReturn Seek(size_t offset, aiOrigin origin)


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Wed Aug 28 2019 04:01:51