TuttleOFX  1
CloudPointData.cpp
Go to the documentation of this file.
00001 #include <GL/glew.h> // need to be included before gl.h
00002 
00003 #include "CloudPointData.hpp"
00004 
00005 #include <tuttle/plugin/opengl/gl.h>
00006 
00007 #include <terry/algorithm/transform_pixels.hpp>
00008 
00009 
00010 namespace tuttle {
00011 namespace plugin {
00012 namespace colorCubeViewer {
00013         
00014 CloudPointData::CloudPointData(const OfxPointI& size, OfxTime time):
00015 _averageColor(time)     //Selection average constructor (current time is needed)
00016 {
00017         _size = size;   //define first size (current clip number of pixels)
00018         _time = time;   //get current time
00019         
00020         // cloud point VBO
00021         int imgSize = size.x*size.y; // number of pixel in the image
00022         _imgCopy.reserve( imgSize * 0.5 );      //reserve memory for buffer
00023         
00024         //selection buffer 
00025         _selectionCopy.reserve( imgSize * 0.5); //reserve memory for color selection buffer
00026         _spillCopy.reserve( imgSize * 0.5);             //reserve memory for spill selection buffer
00027         
00028         //VBO are not built at this time
00029         _isVBOBuilt = false;                            //cloud point VBO is not built
00030         _isSelectionVBOBuilt = false;           //color selection VBO is not built
00031         _isSpillSelectionVBOBuilt = false;      //spill selection VBO is not built
00032 }
00033 
00034 /**
00035  * Open src clip return if opening has been done (y or n)
00036  * @param clipSrc       source of the plugin
00037  * @param renderScale   current renderScale
00038  */
00039 bool CloudPointData::generateVBOData( OFX::Clip* clipSrc, const OfxPointD& renderScale, const bool vboWithDiscretization, const int discretizationStep)
00040 {       
00041         _isVBOBuilt = false; //VBO is not built anymore
00042         // connection test
00043         if( ! clipSrc->isConnected() )
00044         {       
00045                 return false;
00046         }
00047         boost::scoped_ptr<OFX::Image> src( clipSrc->fetchImage(_time, clipSrc->getCanonicalRod(_time)) );       //scoped pointer of current source clip
00048         // Compatibility tests
00049         if( !src.get() ) // source isn't accessible
00050         {
00051                 std::cout << "src is not accessible (cloud point)" << std::endl;
00052                 return false;
00053         }
00054         if( src->getRowDistanceBytes() == 0 )//if source is wrong
00055         {
00056                 BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00057                 return false;
00058         }
00059         const OfxRectI srcPixelRod = clipSrc->getPixelRod( _time, renderScale ); //get current RoD
00060         if( (clipSrc->getPixelDepth() != OFX::eBitDepthFloat) ||
00061                 (clipSrc->getPixelComponents() == OFX::ePixelComponentNone) )
00062         {
00063                 BOOST_THROW_EXCEPTION( exception::Unsupported() << exception::user() + "Can't compute histogram data with the actual input clip format." );
00064         return false;
00065         }
00066         
00067         if( srcPixelRod != src->getBounds() )// the host does bad things !
00068         {
00069                 // remove overlay... but do not crash.
00070                 TUTTLE_LOG_WARNING( "Image RoD and image bounds are not the same (rod=" << srcPixelRod << " , bounds:" << src->getBounds() << ")." );
00071                 return false;
00072         }
00073         // Compute if source is OK
00074         SView srcView = tuttle::plugin::getGilView<SView>( src.get(), srcPixelRod, eImageOrientationIndependant );      // get current view from source clip
00075         
00076         _imgCopy.clear();                       //clear buffer
00077         if( vboWithDiscretization )     //does user want to discretize the VBO
00078         {
00079                 generateDiscretizedVBOData( srcView, discretizationStep);       //create data and return buffer size
00080         }
00081         else
00082         {
00083                 generateAllPointsVBOData( srcView );                                            // create data and return buffer size
00084         }       
00085         _isVBOBuilt = true; //VBO has been built
00086         return true;
00087 }
00088 
00089 /**
00090  * create the VBO from VBO data (draw function)
00091  */
00092 void CloudPointData::updateVBO()
00093 {
00094         //point cloud VBO
00095         _imgVBO.createVBO( &(_imgCopy.front()), _imgCopy.size() / 3 );  //generate VBO to draw
00096         _imgVBO._color = true;                                                                                  //activate color for VBO
00097         //color selection VBO
00098         _selectionColorVBO._colorDifferent = true;                                                                                                                                                                      //color buffer is not the same than vertex buffer
00099         _selectionColorVBO._color = false;                                                                                                                                                                                      //disable color for VBO
00100         _selectionColorVBO.createVBO(&(_selectionCopy.front()), _selectionCopy.size()/3,GL_STATIC_DRAW ,&(_selectionCopy.front())); //generate color selection VBO to draw
00101         //spill selection VBO
00102         _selectionSpillVBO._colorDifferent = true;                                                                                                                                                                      //color buffer is not the same than vertex buffer
00103         _selectionSpillVBO._color = false;                                                                                                                                                                                      //disable color for VBO
00104         _selectionSpillVBO.createVBO(&(_spillCopy.front()), _spillCopy.size()/3,GL_STATIC_DRAW ,&(_spillCopy.front()));                         //generate spill selection VBO to draw
00105 }
00106 
00107 /*
00108  * Copy RGB channels of the clip source into a buffer
00109  */
00110 int CloudPointData::generateAllPointsVBOData(SView srcView)
00111 {
00112         //compute buffer size
00113         int size = (int)(srcView.height()*srcView.width());     //return size : full image here
00114 
00115         //copy full image into buffer
00116         Pixel_copy funct( _imgCopy );                                           //functor declaration   
00117         //treatment
00118         terry::algorithm::transform_pixels( srcView, funct );           //transform pixel did with functor reference
00119         return size;
00120 }
00121 
00122 /*
00123  * Copy discretization RGB channels of the clip source into a buffer
00124  */
00125 int CloudPointData::generateDiscretizedVBOData(SView srcView, const int& discretizationStep )
00126 {
00127         //compute buffer size
00128         int size = (int)(srcView.height()*srcView.width());                                             //return size : full image here
00129 
00130         //Create and use functor to get discretize data  (functor with template)
00131         Pixel_copy_discretization<SPixel> funct(_imgCopy,discretizationStep);   //functor declaration   
00132         terry::algorithm::transform_pixels( srcView, funct);                                                    //with functor reference
00133         funct.convertSetDataToVectorData();                                                                             //copy functor data to _imgCopy data
00134         size = _imgCopy.size();                                                                                                 //change size
00135         return size;
00136 }
00137 
00138 /*
00139  * 
00140  */
00141 bool CloudPointData::generateColorSelectionVBO(OFX::Clip* clipColor, const OfxPointD& renderScale, bool vboWithDiscretization, int discretizationStep)
00142 {
00143         _isSelectionVBOBuilt = false; // selection VBO is not built 
00144         // connection test
00145         if( ! clipColor->isConnected() )
00146         {       
00147                 return false;
00148         }
00149         
00150         boost::scoped_ptr<OFX::Image> src( clipColor->fetchImage(_time, clipColor->getCanonicalRod(_time)) );   //scoped pointer of current color clip
00151         
00152         // Compatibility tests
00153         if( !src.get() ) // color clip source isn't accessible
00154         {
00155                 std::cout << "src is not accessible (color clip)" << std::endl;
00156                 return false;
00157         }
00158         if( src->getRowDistanceBytes() == 0 )//if source is wrong
00159         {
00160                 BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00161                 return false;
00162         }
00163         const OfxRectI srcPixelRod = clipColor->getPixelRod( _time, renderScale ); //get current RoD
00164         if( (clipColor->getPixelDepth() != OFX::eBitDepthFloat) ||
00165                 (clipColor->getPixelComponents() == OFX::ePixelComponentNone) )
00166         {
00167                 BOOST_THROW_EXCEPTION( exception::Unsupported() << exception::user() + "Can't compute histogram data with the actual input clip format." );
00168         return false;
00169         }
00170         if( srcPixelRod != src->getBounds() )// the host does bad things !
00171         {
00172                 // remove overlay... but do not crash.
00173                 TUTTLE_LOG_WARNING( "Image RoD and image bounds are not the same (rod=" << srcPixelRod << " , bounds:" << src->getBounds() << ")." );
00174                 return false;
00175         }
00176         // Compute if source is OK
00177         SView srcView = tuttle::plugin::getGilView<SView>( src.get(), srcPixelRod, eImageOrientationIndependant );      // get current view from source clip
00178 
00179         if(vboWithDiscretization) //there is discretization on VBO
00180         {
00181                 //treatment VBO discretization (maybe)
00182         }
00183         //VBO without discretization
00184         generateAllPointsSelectionVBOData(srcView); //generate a selection VBO without discretization
00185         
00186         _isSelectionVBOBuilt = true;    // selection VBO is not built 
00187         return true;                                    // treatment has been done correctly
00188 }
00189 
00190 /*
00191  * Copy RGB channels of the selected pixels in clip source into a buffer
00192  */
00193 int CloudPointData::generateAllPointsSelectionVBOData(SView srcView)
00194 {
00195         //compute buffer size
00196         int size;                                //returned size
00197         bool isSelection = true; //current operations are on selected pixels
00198         
00199         //clear selection copy
00200         _selectionCopy.clear();                                                         //clear selection VBO data
00201         
00202         //copy full image into buffer
00203         Pixel_copy funct(_selectionCopy, isSelection);          //functor declaration creation  
00204         //treatment
00205         terry::algorithm::transform_pixels( srcView, funct );           //transform pixel did with functor reference
00206         size = _selectionCopy.size();                                           //get current size of VBO
00207 
00208         return size;                                    //return size of VBO buffers (same color and vertex)
00209 }
00210 
00211 /*
00212  * 
00213  */
00214 bool CloudPointData::generateSpillSelectionVBO(OFX::Clip* clipSpill, const OfxPointD& renderScale, bool vboWithDiscretization, int discretizationStep)
00215 {
00216         _isSpillSelectionVBOBuilt = false; // selection VBO is not built 
00217         // connection test
00218         if( ! clipSpill->isConnected() )
00219         {       
00220                 return false;
00221         }
00222         
00223         boost::scoped_ptr<OFX::Image> src( clipSpill->fetchImage(_time, clipSpill->getCanonicalRod(_time)) );   //scoped pointer of current color clip
00224         
00225         // Compatibility tests
00226         if( !src.get() ) // color clip source isn't accessible
00227         {
00228                 std::cout << "src is not accessible (spill clip)" << std::endl;
00229                 return false;
00230         }
00231         if( src->getRowDistanceBytes() == 0 )//if source is wrong
00232         {
00233                 BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00234                 return false;
00235         }
00236         const OfxRectI srcPixelRod = clipSpill->getPixelRod( _time, renderScale ); //get current RoD
00237         if( (clipSpill->getPixelDepth() != OFX::eBitDepthFloat) ||
00238                 (clipSpill->getPixelComponents() == OFX::ePixelComponentNone) )
00239         {
00240                 BOOST_THROW_EXCEPTION( exception::Unsupported() << exception::user() + "Can't compute histogram data with the actual input clip format." );
00241         return false;
00242         }
00243         if( srcPixelRod != src->getBounds() )// the host does bad things !
00244         {
00245                 // remove overlay... but do not crash.
00246                 TUTTLE_LOG_WARNING( "Image RoD and image bounds are not the same (rod=" << srcPixelRod << " , bounds:" << src->getBounds() << ")." );
00247                 return false;
00248         }
00249         // Compute if source is OK
00250         SView srcView = tuttle::plugin::getGilView<SView>( src.get(), srcPixelRod, eImageOrientationIndependant );      // get current view from source clip
00251 
00252         if( vboWithDiscretization ) //there is discretization on VBO
00253         {
00254                 //treatment VBO discretization (maybe)
00255         }
00256         //VBO without discretization
00257         generateAllPointsSpillVBOData( srcView ); //generate a selection VBO without discretization
00258         _isSpillSelectionVBOBuilt = true;       // selection VBO is not built 
00259         return true;                                    // treatment has been done correctly
00260 }
00261 
00262 /*
00263  * Copy RGB channels of the selected pixels in clip source into a buffer
00264  */
00265 int CloudPointData::generateAllPointsSpillVBOData(SView srcView)
00266 {
00267         //compute buffer size
00268         int size;                                //returned size
00269         bool isSelection = true; //current operations are on selected pixels
00270         
00271         //clear selection copy
00272         _spillCopy.clear();                                                             //clear selection VBO data
00273         
00274         //copy full image into buffer
00275         Pixel_copy funct(_spillCopy, isSelection);              //functor declaration creation  
00276         //treatment
00277         terry::algorithm::transform_pixels( srcView, funct );   //transform pixel did with functor reference
00278         
00279         size = _spillCopy.size();                                               //get current size of VBO
00280         return size;                                                                    //return size of VBO buffers (same color and vertex)
00281 }
00282 
00283 
00284 ////////////////////////////////////////////////////////////////////////////////
00285 //                           CloudPoint::VBO                                   //
00286 ////////////////////////////////////////////////////////////////////////////////
00287 
00288 /**
00289  * Constructor
00290  * @param data  data used to create VBO
00291  * @param size  size of VBO     
00292  * @param usage usage of VBO
00293  */
00294 void CloudPointData::VBO::createVBO( const void* data, int size, GLenum usage, const void* dataColor )
00295 {
00296         _size = size;
00297         genBuffer( _id, data, size, GL_ARRAY_BUFFER, usage );
00298 }
00299 
00300 /**
00301  * destroy a VBO
00302  * If VBO id is not valid or zero, then OpenGL ignores it silently.
00303  */
00304 void CloudPointData::VBO::deleteVBO( )
00305 {
00306         if( _id != 0 )  //if VBO exists
00307         {
00308                 glDeleteBuffers( 1, &_id );
00309                 _id = 0; // 0 is reserved, glGenBuffersARB() will return non-zero id if success
00310         }
00311         if( _idColor != 0)
00312         {
00313                 glDeleteBuffers(1, &_idColor); //delete color buffer 
00314                 _idColor = 0; //reset color id
00315         }
00316 }
00317 
00318 /**
00319  * generate vertex buffer object and bind it with its data
00320  * You must give 2 hints about data usage; target and mode, so that OpenGL can
00321  * decide which data should be stored and its location.
00322  * VBO works with 2 different targets; GL_ARRAY_BUFFER for vertex arrays
00323  * and GL_ELEMENT_ARRAY_BUFFER for index array in glDrawElements().
00324  * The default target is GL_ARRAY_BUFFER.
00325  * By default, usage mode is set as GL_STATIC_DRAW.
00326  * Other usages are GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY,
00327  * GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY,
00328  * GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY.
00329  */
00330 void CloudPointData::VBO::genBuffer( unsigned int& id, const void* data, int size, GLenum target, GLenum usage )
00331 {
00332         //Test if buffer is not already existing
00333         if( id != 0 )           //if id is not null
00334                 deleteVBO( );   //delete current VBO
00335         
00336         const int dataSize = size * 3 * sizeof(float); //current size of data
00337         
00338         //Buffer creation
00339         glGenBuffers( 1, &(_id) );                                              // create a VBO
00340         glBindBuffer( target, _id );                                    // activate VBO id to use
00341         glBufferData( target, dataSize, data, usage );  // upload data to video card
00342 
00343         
00344         // check data size in VBO is same as input array, if not return 0 and delete VBO
00345         int bufferSize = 0;
00346         glGetBufferParameteriv( target, GL_BUFFER_SIZE, &bufferSize );
00347         if( dataSize != bufferSize ) //mismatch between data size and input array (control)
00348         {
00349                 deleteVBO( );
00350                 std::cout << "[createVBO()] Mismatch between Data size and input array" << std::endl;
00351         }
00352 }
00353 
00354 void CloudPointData::VBO::genBufferColor( unsigned int& idColor, const void* data, int size, GLenum target, GLenum usage )
00355 {
00356         //test if current VBO is already existing
00357         if( idColor != 0 )      //if idColor is not null
00358                 deleteVBO( );   //delete current VBO
00359 
00360         const int dataSize = size * 3 * sizeof(float);
00361 
00362         glGenBuffers( 1, &(_idColor) );                                 // create a VBO
00363         glBindBuffer( target, _idColor );                               // activate VBO id to use
00364         glBufferData( target, dataSize, data, usage );  // upload data to video card
00365 
00366         // check data size in VBO is same as input array, if not return 0 and delete VBO
00367         int bufferSize = 0;
00368         glGetBufferParameteriv( target, GL_BUFFER_SIZE, &bufferSize );
00369         if( dataSize != bufferSize ) //mismatch between data size and input array (control)
00370         {
00371                 deleteVBO( );
00372                 std::cout << "[createVBO()] Mismatch between Data size and input array" << std::endl;
00373         }
00374 }
00375 
00376 /*
00377  * Draw the current VBO on screen
00378  */
00379 void CloudPointData::VBO::draw()
00380 {
00381         if( _id && _size )
00382         {
00383                 // bind VBOs with IDs and set the buffer offsets of the bound VBOs
00384                 // When buffer object is bound with its ID, all pointers in gl*Pointer()
00385                 // are treated as offset instead of real pointer.
00386                 glBindBuffer( GL_ARRAY_BUFFER, _id );
00387                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
00388                 glEnableClientState( GL_VERTEX_ARRAY ); // enable vertex arrays
00389 
00390                 if( _color ) //draw vector using color
00391                 {
00392                         if(_colorDifferent) //color and vertex buffers are not the same
00393                         {
00394                                 glBindBuffer(GL_ARRAY_BUFFER, _idColor); //bind new color buffer
00395                         }
00396                         glColorPointer( 3, GL_FLOAT, 0, 0 ); //point buffer which is used for colors (same than vertex or not)
00397                         glEnableClientState( GL_COLOR_ARRAY );
00398                 }
00399 
00400                 glDrawArrays( GL_POINTS, 0, _size );
00401 
00402                 glDisableClientState( GL_VERTEX_ARRAY ); // disable vertex arrays
00403 
00404                 if( _color )
00405                         glDisableClientState( GL_COLOR_ARRAY );
00406 
00407 
00408                 // it is good idea to release VBOs with ID 0 after use.
00409                 // Once bound with 0, all pointers in gl*Pointer() behave as real
00410                 // pointer, so, normal vertex array operations are re-activated
00411                 glBindBuffer( GL_ARRAY_BUFFER, 0 );
00412         }
00413 }
00414 
00415 
00416 }
00417 }
00418 }