point_cloud.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, 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 "rviz_interaction_tools/point_cloud.h"
00031 #include <ros/assert.h>
00032 
00033 #include <OGRE/OgreSceneManager.h>
00034 #include <OGRE/OgreSceneNode.h>
00035 #include <OGRE/OgreVector3.h>
00036 #include <OGRE/OgreQuaternion.h>
00037 #include <OGRE/OgreManualObject.h>
00038 #include <OGRE/OgreMaterialManager.h>
00039 #include <OGRE/OgreBillboardSet.h>
00040 #include <OGRE/OgreBillboard.h>
00041 #include <OGRE/OgreTexture.h>
00042 #include <OGRE/OgreTextureManager.h>
00043 
00044 #include <sstream>
00045 
00046 #define VERTEX_BUFFER_CAPACITY (36 * 1024 * 10)
00047 
00048 namespace rviz_interaction_tools
00049 {
00050 
00051 static float g_point_vertices[3] =
00052 {
00053   0.0f, 0.0f, 0.0f
00054 };
00055 
00056 Ogre::String PointCloud::sm_Type = "RvizInteractionToolsPointCloud";
00057 
00058 PointCloud::PointCloud()
00059 : bounding_radius_( 0.0f )
00060 , point_count_( 0 )
00061 , current_mode_supports_geometry_shader_(false)
00062 {
00063   setMaterial( "BaseWhiteNoLighting" );
00064   clear();
00065 }
00066 
00067 PointCloud::~PointCloud()
00068 {
00069 }
00070 
00071 const Ogre::AxisAlignedBox& PointCloud::getBoundingBox() const
00072 {
00073   return bounding_box_;
00074 }
00075 
00076 float PointCloud::getBoundingRadius() const
00077 {
00078   return bounding_radius_;
00079 }
00080 
00081 void PointCloud::getWorldTransforms(Ogre::Matrix4* xform) const
00082 {
00083   *xform = _getParentNodeFullTransform();
00084 }
00085 
00086 void PointCloud::clear()
00087 {
00088   point_count_ = 0;
00089   bounding_box_.setNull();
00090   bounding_radius_ = 0.0f;
00091 
00092   V_PointCloudRenderable::iterator it = renderables_.begin();
00093   V_PointCloudRenderable::iterator end = renderables_.end();
00094   for (; it != end; ++it)
00095   {
00096     (*it)->getRenderOperation()->vertexData->vertexStart = 0;
00097     (*it)->getRenderOperation()->vertexData->vertexCount = 0;
00098   }
00099 
00100   if (getParentSceneNode())
00101   {
00102     getParentSceneNode()->needUpdate();
00103   }
00104 }
00105 
00106 void PointCloud::regenerateAll()
00107 {
00108   if (point_count_ == 0)
00109   {
00110     return;
00111   }
00112 
00113   V_Point points;
00114   points.swap(points_);
00115   uint32_t count = point_count_;
00116 
00117   clear();
00118 
00119   addPoints(&points.front(), count);
00120 }
00121 
00122 void PointCloud::setMaterial( const Ogre::String& material_name )
00123 {
00124   current_material_ = Ogre::MaterialManager::getSingleton().getByName( material_name );
00125 
00126   bool geom_support_changed = false;
00127   Ogre::Technique* best = current_material_->getBestTechnique();
00128   if (best)
00129   {
00130     if (current_material_->getBestTechnique()->getName() == "gp")
00131     {
00132       if (!current_mode_supports_geometry_shader_)
00133       {
00134         geom_support_changed = true;
00135       }
00136 
00137       current_mode_supports_geometry_shader_ = true;
00138 
00139       //ROS_INFO("Using geometry shader");
00140     }
00141     else
00142     {
00143       if (current_mode_supports_geometry_shader_)
00144       {
00145         geom_support_changed = true;
00146       }
00147 
00148       current_mode_supports_geometry_shader_ = false;
00149     }
00150   }
00151   else
00152   {
00153     geom_support_changed = true;
00154     current_mode_supports_geometry_shader_ = false;
00155 
00156     ROS_ERROR("No techniques available for material [%s]", current_material_->getName().c_str());
00157   }
00158 
00159   if (geom_support_changed)
00160   {
00161     renderables_.clear();
00162   }
00163 
00164   V_PointCloudRenderable::iterator it = renderables_.begin();
00165   V_PointCloudRenderable::iterator end = renderables_.end();
00166   for (; it != end; ++it)
00167   {
00168     (*it)->setMaterial(current_material_->getName());
00169   }
00170 
00171   regenerateAll();
00172 }
00173 
00174 void PointCloud::setRenderQueueGroup( Ogre::uint8 queueID )
00175 {
00176   Ogre::MovableObject::setRenderQueueGroup( queueID );
00177   V_PointCloudRenderable::iterator it = renderables_.begin();
00178   V_PointCloudRenderable::iterator end = renderables_.end();
00179   for (; it != end; ++it)
00180   {
00181     (*it)->setRenderQueueGroup( queueID );
00182     ROS_INFO( "Setting render queue group %d", queueID );
00183   }
00184 }
00185 
00186 void PointCloud::addPoints(Point* points, uint32_t num_points)
00187 {
00188   if (num_points == 0)
00189   {
00190     return;
00191   }
00192 
00193   if ( points_.size() < point_count_ + num_points )
00194   {
00195     points_.resize( point_count_ + num_points );
00196   }
00197 
00198   Point* begin = &points_.front() + point_count_;
00199   memcpy( begin, points, sizeof( Point ) * num_points );
00200 
00201   uint32_t vpp = getVerticesPerPoint();
00202   Ogre::RenderOperation::OperationType op_type = Ogre::RenderOperation::OT_POINT_LIST;
00203 
00204   float* vertices = 0;
00205   if (current_mode_supports_geometry_shader_)
00206   {
00207     vertices = g_point_vertices;
00208   }
00209   else
00210   {
00211     vertices = g_point_vertices;
00212   }
00213 
00214   PointCloudRenderablePtr rend;
00215   Ogre::HardwareVertexBufferSharedPtr vbuf;
00216   void* vdata = 0;
00217   Ogre::RenderOperation* op = 0;
00218   float* fptr = 0;
00219 
00220   Ogre::AxisAlignedBox aabb;
00221   aabb.setNull();
00222   uint32_t current_vertex_count = 0;
00223   bounding_radius_ = 0.0f;
00224   uint32_t vertex_size = 0;
00225   for (uint32_t current_point = 0; current_point < num_points; ++current_point)
00226   {
00227     while (current_vertex_count >= VERTEX_BUFFER_CAPACITY || !rend)
00228     {
00229       if (rend)
00230       {
00231         ROS_ASSERT(current_vertex_count == VERTEX_BUFFER_CAPACITY);
00232 
00233         op->vertexData->vertexCount = VERTEX_BUFFER_CAPACITY - op->vertexData->vertexStart;
00234         ROS_ASSERT(op->vertexData->vertexCount + op->vertexData->vertexStart <= VERTEX_BUFFER_CAPACITY);
00235         vbuf->unlock();
00236         rend->setBoundingBox(aabb);
00237       }
00238 
00239       rend = getOrCreateRenderable();
00240       vbuf = rend->getBuffer();
00241       vdata = vbuf->lock(Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
00242 
00243       op = rend->getRenderOperation();
00244       op->operationType = op_type;
00245       current_vertex_count = op->vertexData->vertexStart + op->vertexData->vertexCount;
00246 
00247       vertex_size = op->vertexData->vertexDeclaration->getVertexSize(0);
00248       uint32_t data_pos = current_vertex_count * vertex_size;
00249       fptr = (float*)((uint8_t*)vdata + data_pos);
00250 
00251       aabb.setNull();
00252     }
00253 
00254     const Point& p = points[current_point];
00255     float x = p.x;
00256     float y = p.y;
00257     float z = p.z;
00258     uint32_t color = p.color;
00259 
00260     Ogre::Vector3 pos(x, y, z);
00261     aabb.merge(pos);
00262     bounding_box_.merge( pos );
00263     bounding_radius_ = std::max( bounding_radius_, pos.squaredLength() );
00264 
00265     for (uint32_t j = 0; j < vpp; ++j, ++current_vertex_count)
00266     {
00267       *fptr++ = x;
00268       *fptr++ = y;
00269       *fptr++ = z;
00270 
00271       if (!current_mode_supports_geometry_shader_)
00272       {
00273         *fptr++ = vertices[(j*3)];
00274         *fptr++ = vertices[(j*3) + 1];
00275         *fptr++ = vertices[(j*3) + 2];
00276       }
00277 
00278       uint32_t* iptr = (uint32_t*)fptr;
00279       *iptr = color;
00280       ++fptr;
00281 
00282       ROS_ASSERT((uint8_t*)fptr <= (uint8_t*)vdata + VERTEX_BUFFER_CAPACITY * vertex_size);
00283     }
00284   }
00285 
00286   op->vertexData->vertexCount = current_vertex_count - op->vertexData->vertexStart;
00287   rend->setBoundingBox(aabb);
00288   ROS_ASSERT(op->vertexData->vertexCount + op->vertexData->vertexStart <= VERTEX_BUFFER_CAPACITY);
00289 
00290   vbuf->unlock();
00291 
00292   point_count_ += num_points;
00293 
00294   shrinkRenderables();
00295 
00296   if (getParentSceneNode())
00297   {
00298     getParentSceneNode()->needUpdate();
00299   }
00300 }
00301 
00302 void PointCloud::shrinkRenderables()
00303 {
00304   while (!renderables_.empty())
00305   {
00306     PointCloudRenderablePtr rend = renderables_.back();
00307     Ogre::RenderOperation* op = rend->getRenderOperation();
00308     if (op->vertexData->vertexCount == 0)
00309     {
00310       renderables_.pop_back();
00311     }
00312     else
00313     {
00314       break;
00315     }
00316   }
00317 }
00318 
00319 void PointCloud::_notifyCurrentCamera(Ogre::Camera* camera)
00320 {
00321   MovableObject::_notifyCurrentCamera( camera );
00322 }
00323 
00324 void PointCloud::_updateRenderQueue(Ogre::RenderQueue* queue)
00325 {
00326   V_PointCloudRenderable::iterator it = renderables_.begin();
00327   V_PointCloudRenderable::iterator end = renderables_.end();
00328   for (; it != end; ++it)
00329   {
00330     queue->addRenderable((*it).get());
00331   }
00332 }
00333 
00334 void PointCloud::_notifyAttached(Ogre::Node *parent, bool isTagPoint)
00335 {
00336   MovableObject::_notifyAttached(parent, isTagPoint);
00337 }
00338 
00339 uint32_t PointCloud::getVerticesPerPoint()
00340 {
00341   return 1;
00342 }
00343 
00344 PointCloudRenderablePtr PointCloud::getOrCreateRenderable()
00345 {
00346   V_PointCloudRenderable::iterator it = renderables_.begin();
00347   V_PointCloudRenderable::iterator end = renderables_.end();
00348   for (; it != end; ++it)
00349   {
00350     const PointCloudRenderablePtr& rend = *it;
00351     Ogre::RenderOperation* op = rend->getRenderOperation();
00352     if (op->vertexData->vertexCount + op->vertexData->vertexStart < VERTEX_BUFFER_CAPACITY)
00353     {
00354       return rend;
00355     }
00356   }
00357 
00358   PointCloudRenderablePtr rend(new PointCloudRenderable(this, !current_mode_supports_geometry_shader_));
00359   rend->setMaterial(current_material_->getName());
00360   rend->setRenderQueueGroup( getRenderQueueGroup() );
00361   ROS_INFO( "Setting render queue group %d", getRenderQueueGroup() );
00362 
00363   if (getParentSceneNode())
00364   {
00365     getParentSceneNode()->attachObject(rend.get());
00366   }
00367   renderables_.push_back(rend);
00368 
00369   return rend;
00370 }
00371 
00372 #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6)
00373 void PointCloud::visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables)
00374 {
00375   V_PointCloudRenderable::iterator it = renderables_.begin();
00376   V_PointCloudRenderable::iterator end = renderables_.end();
00377   for (; it != end; ++it)
00378   {
00379     visitor->visit( it->get(), 0, debugRenderables, 0 );
00380   }
00381 }
00382 #endif
00383 
00384 
00388 
00389 PointCloudRenderable::PointCloudRenderable(PointCloud* parent, bool use_tex_coords)
00390 : parent_(parent)
00391 {
00392   // Initialize render operation
00393   mRenderOp.operationType = Ogre::RenderOperation::OT_POINT_LIST;
00394   mRenderOp.useIndexes = false;
00395   mRenderOp.vertexData = new Ogre::VertexData;
00396   mRenderOp.vertexData->vertexStart = 0;
00397   mRenderOp.vertexData->vertexCount = 0;
00398 
00399   Ogre::VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
00400   size_t offset = 0;
00401 
00402   decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
00403   offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00404 
00405   if (use_tex_coords)
00406   {
00407     decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, 0);
00408     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00409   }
00410 
00411   decl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
00412 
00413   Ogre::HardwareVertexBufferSharedPtr vbuf =
00414     Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
00415       mRenderOp.vertexData->vertexDeclaration->getVertexSize(0),
00416       VERTEX_BUFFER_CAPACITY,
00417       Ogre::HardwareBuffer::HBU_DYNAMIC);
00418 
00419   // Bind buffer
00420   mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf);
00421 }
00422 
00423 PointCloudRenderable::~PointCloudRenderable()
00424 {
00425   delete mRenderOp.vertexData;
00426   delete mRenderOp.indexData;
00427 }
00428 
00429 Ogre::HardwareVertexBufferSharedPtr PointCloudRenderable::getBuffer()
00430 {
00431   return mRenderOp.vertexData->vertexBufferBinding->getBuffer(0);
00432 }
00433 
00434 void PointCloudRenderable::_notifyCurrentCamera(Ogre::Camera* camera)
00435 {
00436   SimpleRenderable::_notifyCurrentCamera( camera );
00437 }
00438 
00439 Ogre::Real PointCloudRenderable::getBoundingRadius(void) const
00440 {
00441   return Ogre::Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength()));
00442 }
00443 
00444 Ogre::Real PointCloudRenderable::getSquaredViewDepth(const Ogre::Camera* cam) const
00445 {
00446   Ogre::Vector3 vMin, vMax, vMid, vDist;
00447    vMin = mBox.getMinimum();
00448    vMax = mBox.getMaximum();
00449    vMid = ((vMax - vMin) * 0.5) + vMin;
00450    vDist = cam->getDerivedPosition() - vMid;
00451 
00452    return vDist.squaredLength();
00453 }
00454 
00455 void PointCloudRenderable::getWorldTransforms(Ogre::Matrix4* xform) const
00456 {
00457    *xform = m_matWorldTransform * parent_->getParentNode()->_getFullTransform();
00458 }
00459 
00460 const Ogre::LightList& PointCloudRenderable::getLights() const
00461 {
00462   return parent_->queryLights();
00463 }
00464 
00465 void PointCloudRenderable::_updateRenderQueue(Ogre::RenderQueue* queue)
00466 {
00467     queue->addRenderable( this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
00468 }
00469 
00470 } // namespace rviz_interaction_tools


rviz_interaction_tools
Author(s): David Gossow
autogenerated on Thu Jan 2 2014 11:37:58