mesh_loader.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <rve_render_server/mesh_loader.h>
00031 #include <rve_render_server/mesh.h>
00032 #include <rve_render_server/submesh.h>
00033 #include <rve_render_server/material.h>
00034 #include <rve_render_server/init.h>
00035 #include <rve_render_server/renderer.h>
00036 
00037 #include <rve_mesh_loader/loader.h>
00038 #include <rve_msgs/Mesh.h>
00039 
00040 #include <rve_common/uuid.h>
00041 
00042 #include <resource_retriever/retriever.h>
00043 
00044 #include <OGRE/OgreMeshManager.h>
00045 #include <OGRE/OgreMeshSerializer.h>
00046 #include <OGRE/OgreSubMesh.h>
00047 #include <OGRE/OgreHardwareBufferManager.h>
00048 #include <OGRE/OgreRoot.h>
00049 
00050 #include <boost/filesystem.hpp>
00051 
00052 namespace fs = boost::filesystem;
00053 
00054 namespace rve_render_server
00055 {
00056 
00057 MaterialPtr createMaterial(const rve_msgs::Material& mat)
00058 {
00059   MaterialPtr out(new Material(mat.id));
00060   out->setMaterial(mat);
00061   getRenderer()->addMaterial(out->getID(), out);
00062   return out;
00063 }
00064 
00065 void createMaterialsForMesh(const rve_msgs::Mesh& input_mesh)
00066 {
00067   for (uint32_t i = 0; i < input_mesh.materials.size(); i++)
00068   {
00069     const rve_msgs::Material& in_mat = input_mesh.materials[i];
00070     createMaterial(in_mat);
00071   }
00072 }
00073 
00074 
00075 MeshPtr convertMesh(const rve_common::UUID& id, const rve_msgs::Mesh& input_mesh)
00076 {
00077   createMaterialsForMesh(input_mesh);
00078 
00079   Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(id.toString(), ROS_PACKAGE_NAME);
00080 
00081   Ogre::AxisAlignedBox aabb;
00082   float radius = 0.0;
00083   for (size_t i = 0; i < input_mesh.submeshes.size(); ++i)
00084   {
00085     const rve_msgs::SubMesh& input_submesh = input_mesh.submeshes[i];
00086 
00087     bool has_normals = !input_submesh.normals.empty();
00088 
00089     Ogre::SubMesh* submesh = mesh->createSubMesh();
00090     submesh->useSharedVertices = false;
00091     submesh->vertexData = new Ogre::VertexData();
00092     Ogre::VertexData* vertex_data = submesh->vertexData;
00093     Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration;
00094 
00095     size_t offset = 0;
00096     // positions
00097     vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
00098     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00099 
00100     // normals
00101     if (has_normals)
00102     {
00103       ROS_ASSERT(input_submesh.normals.size() == input_submesh.positions.size());
00104 
00105       vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
00106       offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00107     }
00108 
00109     // vertex colors
00110     for (size_t j = 0; j < input_submesh.colors.size(); ++j)
00111     {
00112       ROS_ASSERT(input_submesh.colors[j].array.size() == input_submesh.positions.size());
00113       vertex_decl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE, j);
00114       offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
00115     }
00116 
00117     // Texture coordinates
00118     uint32_t texcoord_index = 0;
00119     for (size_t j = 0; j < input_submesh.tex_coords.size(); ++j)
00120     {
00121      ROS_ASSERT(input_submesh.tex_coords[j].array.size() == input_submesh.positions.size());
00122      ROS_ASSERT(input_submesh.tex_coords[j].dims <= 3);
00123 
00124      Ogre::VertexElementType type = Ogre::VET_FLOAT1;
00125      if (input_submesh.tex_coords[j].dims == 2)
00126      {
00127        type = Ogre::VET_FLOAT2;
00128      }
00129      else if (input_submesh.tex_coords[j].dims == 3)
00130      {
00131        type = Ogre::VET_FLOAT3;
00132      }
00133 
00134      vertex_decl->addElement(0, offset, type, Ogre::VES_TEXTURE_COORDINATES, texcoord_index++);
00135      offset += Ogre::VertexElement::getTypeSize(type);
00136     }
00137 
00138     // Tangents
00139     if (!input_submesh.tangents.empty())
00140     {
00141       // Tangents
00142       vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT, 0);
00143       offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00144     }
00145 
00146     // allocate the vertex buffer
00147     vertex_data->vertexCount = input_submesh.positions.size();
00148     Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertex_decl->getVertexSize(0),
00149                                                                           vertex_data->vertexCount,
00150                                                                           Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00151                                                                           false);
00152 
00153     vertex_data->vertexBufferBinding->setBinding(0, vbuf);
00154     float* vertices = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00155 
00156     // Add the vertices
00157     for (size_t j = 0; j < input_submesh.positions.size(); j++)
00158     {
00159       const rve_msgs::Vector3& p = input_submesh.positions[j];
00160       *vertices++ = p.x;
00161       *vertices++ = p.y;
00162       *vertices++ = p.z;
00163 
00164       Ogre::Vector3 ogre_pos(p.x, p.y, p.z);
00165       aabb.merge(ogre_pos);
00166       float dist = ogre_pos.length();
00167       if (dist > radius)
00168       {
00169         radius = dist;
00170       }
00171 
00172       if (has_normals)
00173       {
00174         const rve_msgs::Vector3& n = input_submesh.normals[j];
00175         *vertices++ = n.x;
00176         *vertices++ = n.y;
00177         *vertices++ = n.z;
00178       }
00179 
00180       for (size_t k = 0; k < input_submesh.colors.size(); ++k)
00181       {
00182         const std_msgs::ColorRGBA& color = input_submesh.colors[k].array[j];
00183         Ogre::Root::getSingleton().convertColourValue(Ogre::ColourValue(color.r, color.g, color.b, color.a), reinterpret_cast<uint32_t*>(vertices));
00184         ++vertices;
00185       }
00186 
00187       for (size_t k = 0; k < input_submesh.tex_coords.size(); ++k)
00188       {
00189         const rve_msgs::TexCoord& tex = input_submesh.tex_coords[k].array[j];
00190         for (uint32_t l = 0; l < input_submesh.tex_coords[k].dims; ++l)
00191         {
00192           *vertices++ = tex.uvw[l];
00193         }
00194       }
00195 
00196       if (!input_submesh.tangents.empty())
00197       {
00198         const rve_msgs::Vector3& t = input_submesh.tangents[j];
00199         *vertices++ = t.x;
00200         *vertices++ = t.y;
00201         *vertices++ = t.z;
00202       }
00203     }
00204 
00205     submesh->indexData->indexCount = input_submesh.indices.size();
00206 
00207     // allocate index buffer
00208     submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
00209                                              Ogre::HardwareIndexBuffer::IT_16BIT,
00210                                              submesh->indexData->indexCount,
00211                                              Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00212                                              false);
00213 
00214     Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
00215     uint16_t* indices = static_cast<uint16_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00216 
00217     // add the indices
00218     for (uint32_t j = 0; j < input_submesh.indices.size(); j++)
00219     {
00220       *indices++ = input_submesh.indices[j];
00221     }
00222 
00223     // Unlock
00224     vbuf->unlock();
00225     ibuf->unlock();
00226   }
00227 
00228   mesh->_setBounds(aabb);
00229   mesh->_setBoundingSphereRadius(radius);
00230 
00231   MeshPtr out_mesh(new Mesh(id, mesh));
00232   // assign materials
00233   for (size_t i = 0; i < input_mesh.submeshes.size(); ++i)
00234   {
00235     int8_t mat_index = input_mesh.submeshes[i].material_index;
00236     if (mat_index >= 0 && mat_index < (int8_t)input_mesh.materials.size())
00237     {
00238       out_mesh->getSubMesh(i)->setMaterialID(input_mesh.materials[mat_index].id);
00239     }
00240   }
00241 
00242   getRenderer()->addMesh(id, out_mesh);
00243 
00244   return out_mesh;
00245 }
00246 
00247 MeshPtr loadMesh(const std::string& resource_path)
00248 {
00249   fs::path model_path(resource_path);
00250   std::string ext = model_path.extension();
00251   // If it's an ogre .mesh, load it directly
00252   if (ext == ".mesh" || ext == ".MESH")
00253   {
00254     resource_retriever::Retriever retriever;
00255     resource_retriever::MemoryResource res;
00256     try
00257     {
00258       res = retriever.get(resource_path);
00259     }
00260     catch (resource_retriever::Exception& e)
00261     {
00262       ROS_ERROR("%s", e.what());
00263       return MeshPtr();
00264     }
00265 
00266     if (res.size == 0)
00267     {
00268       return MeshPtr();
00269     }
00270 
00271     rve_common::UUID id = rve_common::UUID::generate();
00272 
00273     Ogre::MeshSerializer ser;
00274     Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00275     Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(id.toString(), ROS_PACKAGE_NAME);
00276     ser.importMesh(stream, mesh.get());
00277 
00278     MeshPtr out_mesh(new Mesh(id, mesh));
00279     getRenderer()->addMesh(id, out_mesh);
00280     return out_mesh;
00281   }
00282   else
00283   {
00284     rve_msgs::Mesh mesh_msg;
00285     rve_mesh_loader::load(resource_path, mesh_msg);
00286     return convertMesh(rve_common::UUID::generate(), mesh_msg);
00287   }
00288 
00289 }
00290 
00291 } // namespace rve_render_server


rve_render_server
Author(s): Josh Faust
autogenerated on Wed Dec 11 2013 14:31:15