include/cinder/gl/Vbo.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2010, The Barbarian Group
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00006  the following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00009     the following disclaimer.
00010     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00011     the following disclaimer in the documentation and/or other materials provided with the distribution.
00012 
00013  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00014  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00015  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00016  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00017  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00018  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00019  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00020  POSSIBILITY OF SUCH DAMAGE.
00021 */
00022 
00023 #pragma once
00024 
00025 #include "cinder/gl/gl.h"
00026 #include "cinder/TriMesh.h"
00027 
00028 #include <vector>
00029 #include <utility>
00030 
00031 namespace cinder { namespace gl {
00032 
00033 class Vbo {
00034  public:
00035     Vbo() {}
00036     Vbo( GLenum aTarget );
00037     
00038     void        bind();
00039     void        unbind();
00040     
00041     void        bufferData( size_t size, const void *data, GLenum usage );
00042     void        bufferSubData( ptrdiff_t offset, size_t size, const void *data );
00043     
00044     uint8_t*    map( GLenum access );
00045     void        unmap();
00046 
00047     GLenum      getTarget() const { return mObj->mTarget; }
00048     GLuint      getId() const { return mObj->mId; }
00049     
00050  protected:
00051     struct Obj {
00052         Obj( GLenum aTarget );
00053         ~Obj();
00054 
00055         GLenum          mTarget;
00056         GLuint          mId;
00057     };
00058     
00059     std::shared_ptr<Obj>    mObj;
00060 
00061   public:
00063 
00064     typedef std::shared_ptr<Obj> Vbo::*unspecified_bool_type;
00065     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &Vbo::mObj; }
00066     void reset() { mObj.reset(); }
00068 };
00069 
00070 class VboMesh;
00071 typedef std::shared_ptr<VboMesh>    VboMeshRef;
00072 
00073 class VboMesh {
00074  public:
00075     enum { NONE, STATIC, DYNAMIC };
00076     enum { ATTR_INDICES, ATTR_POSITIONS, ATTR_NORMALS, ATTR_COLORS_RGB, ATTR_COLORS_RGBA, ATTR_TEXCOORDS2D_0, ATTR_TEXCOORDS2D_1, ATTR_TEXCOORDS2D_2, ATTR_TEXCOORDS2D_3, ATTR_TEXCOORDS3D_0, ATTR_TEXCOORDS3D_1, ATTR_TEXCOORDS3D_2, ATTR_TEXCOORDS3D_3, ATTR_TOTAL };
00077     enum { ATTR_MAX_TEXTURE_UNIT = 3 };
00078 
00079     struct Layout {
00080         Layout() { initAttributes(); }
00081 
00083         bool    isDefaults() const { for( int a = 0; a < ATTR_TOTAL; ++a ) if( mAttributes[a] != NONE ) return false; return true; }
00084     
00085         bool    hasNormals() const { return hasDynamicNormals() || hasStaticNormals(); }
00086         bool    hasStaticNormals() const { return mAttributes[ATTR_NORMALS] == STATIC; }
00087         bool    hasDynamicNormals() const { return mAttributes[ATTR_NORMALS] == DYNAMIC; }
00088         void    setStaticNormals() { mAttributes[ATTR_NORMALS] = STATIC; }
00089         void    setDynamicNormals() { mAttributes[ATTR_NORMALS] = DYNAMIC; }        
00090 
00091         bool    hasColorsRGB() const { return hasDynamicColorsRGB() || hasStaticColorsRGB(); }
00092         bool    hasStaticColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == STATIC; }
00093         bool    hasDynamicColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == DYNAMIC; }
00094         void    setStaticColorsRGB() { mAttributes[ATTR_COLORS_RGB] = STATIC; mAttributes[ATTR_COLORS_RGBA] = NONE; }
00095         void    setDynamicColorsRGB() { mAttributes[ATTR_COLORS_RGB] = DYNAMIC; mAttributes[ATTR_COLORS_RGBA] = NONE; }     
00096 
00097         bool    hasColorsRGBA() const { return hasDynamicColorsRGBA() || hasStaticColorsRGBA(); }
00098         bool    hasStaticColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == STATIC; }
00099         bool    hasDynamicColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == DYNAMIC; }
00100         void    setStaticColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = STATIC; mAttributes[ATTR_COLORS_RGB] = NONE; }
00101         void    setDynamicColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = DYNAMIC; mAttributes[ATTR_COLORS_RGB] = NONE; }        
00102         
00103         bool    hasTexCoords2d( size_t unit = 0 ) const { return hasDynamicTexCoords2d( unit ) || hasStaticTexCoords2d( unit ); }
00104         bool    hasStaticTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == STATIC; }      
00105         bool    hasDynamicTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == DYNAMIC; }
00106         void    setStaticTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; }
00107         void    setDynamicTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; }
00109         bool    hasStaticTexCoords() const;
00111         bool    hasDynamicTexCoords() const;
00113         bool    hasTexCoords( size_t unit ) const { return ( mAttributes[ATTR_TEXCOORDS2D_0 + unit] != NONE ) || ( mAttributes[ATTR_TEXCOORDS3D_0 + unit] != NONE ); }
00114 
00115         bool    hasTexCoords3d( size_t unit = 0 ) const { return hasDynamicTexCoords3d( unit ) || hasStaticTexCoords3d( unit ); }
00116         bool    hasStaticTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == STATIC; }      
00117         bool    hasDynamicTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == DYNAMIC; }
00118         void    setStaticTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; }
00119         void    setDynamicTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; }
00120 
00121         bool    hasIndices() const { return hasStaticIndices() || hasDynamicIndices(); }
00122         bool    hasStaticIndices() const { return mAttributes[ATTR_INDICES] == STATIC; }
00123         bool    hasDynamicIndices() const { return mAttributes[ATTR_INDICES] == DYNAMIC; }
00124         void    setStaticIndices() { mAttributes[ATTR_INDICES] = STATIC; }
00125         void    setDynamicIndices() { mAttributes[ATTR_INDICES] = DYNAMIC; }
00126 
00127         bool    hasPositions() const { return hasStaticPositions() || hasDynamicPositions(); }
00128         bool    hasStaticPositions() const { return mAttributes[ATTR_POSITIONS] == STATIC; }
00129         bool    hasDynamicPositions() const { return mAttributes[ATTR_POSITIONS] == DYNAMIC; }
00130         void    setStaticPositions() { mAttributes[ATTR_POSITIONS] = STATIC; }
00131         void    setDynamicPositions() { mAttributes[ATTR_POSITIONS] = DYNAMIC; }
00132         
00133         enum CustomAttr { CUSTOM_ATTR_FLOAT, CUSTOM_ATTR_FLOAT2, CUSTOM_ATTR_FLOAT3, CUSTOM_ATTR_FLOAT4, TOTAL_CUSTOM_ATTR_TYPES };
00134         static int sCustomAttrSizes[TOTAL_CUSTOM_ATTR_TYPES];
00135         static GLint sCustomAttrNumComponents[TOTAL_CUSTOM_ATTR_TYPES];
00136         static GLenum sCustomAttrTypes[TOTAL_CUSTOM_ATTR_TYPES];
00137         void    addDynamicCustomFloat() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT, 0 ) ); }
00138         void    addDynamicCustomVec2f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT2, 0 ) ); }
00139         void    addDynamicCustomVec3f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT3, 0 ) ); }
00140         void    addDynamicCustomVec4f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT4, 0 ) ); }
00141 
00142         int                                             mAttributes[ATTR_TOTAL];
00143         std::vector<std::pair<CustomAttr,size_t> >      mCustomDynamic, mCustomStatic; // pair of <types,offset>
00144         
00145      private:
00146         void initAttributes() { for( int a = 0; a < ATTR_TOTAL; ++a ) mAttributes[a] = NONE; }
00147     };
00148 
00149     enum            { INDEX_BUFFER = 0, STATIC_BUFFER, DYNAMIC_BUFFER, TOTAL_BUFFERS };
00150     
00151   protected:
00152     struct Obj {
00153         size_t          mNumIndices, mNumVertices;  
00154 
00155         Vbo             mBuffers[TOTAL_BUFFERS];
00156         size_t          mPositionOffset;
00157         size_t          mNormalOffset;
00158         size_t          mColorRGBOffset, mColorRGBAOffset;      
00159         size_t          mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1];
00160         size_t          mStaticStride, mDynamicStride;  
00161         GLenum          mPrimitiveType;
00162         Layout          mLayout;
00163         std::vector<GLint>      mCustomStaticLocations;
00164         std::vector<GLint>      mCustomDynamicLocations;
00165     };
00166 
00167   public:
00168     class VertexIter;
00169  
00170     VboMesh() {}
00171     explicit VboMesh( const TriMesh &triMesh, Layout layout = Layout() );
00172     explicit VboMesh( const TriMesh2d &triMesh, Layout layout = Layout() );
00173     /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Dynamic data is stored interleaved and static data is planar. **/
00174     VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType );
00175     /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Accepts pointers to preexisting buffers, which may be NULL to request allocation **/
00176     VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType, Vbo *indexBuffer, Vbo *staticBuffer, Vbo *dynamicBuffer );
00177 
00178     static VboMeshRef   create( const TriMesh &triMesh, Layout layout = Layout() ) { return std::shared_ptr<VboMesh>( new VboMesh( triMesh, layout ) ); }
00179     static VboMeshRef   create( const TriMesh2d &triMesh, Layout layout = Layout() ) { return std::shared_ptr<VboMesh>( new VboMesh( triMesh, layout ) ); }
00180     static VboMeshRef   create( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType ) { return std::shared_ptr<VboMesh>( new VboMesh( numVertices, numIndices, layout, primitiveType ) ); }
00181     static VboMeshRef   create( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType, Vbo *indexBuffer, Vbo *staticBuffer, Vbo *dynamicBuffer ) 
00182         { return std::shared_ptr<VboMesh>( new VboMesh( numVertices, numIndices, layout, primitiveType, indexBuffer, staticBuffer, dynamicBuffer ) ); }
00183 
00184 
00185     size_t  getNumIndices() const { return mObj->mNumIndices; }
00186     size_t  getNumVertices() const { return mObj->mNumVertices; }
00187     GLenum  getPrimitiveType() const { return mObj->mPrimitiveType; }
00188     
00189     const Layout&   getLayout() const { return mObj->mLayout; }
00190 
00191     void            bindIndexBuffer() const;
00192     void            enableClientStates() const;
00193     void            disableClientStates() const;
00194     void            bindAllData() const;
00195     static void     unbindBuffers();
00196 
00197     void                        bufferIndices( const std::vector<uint32_t> &indices );
00198     void                        bufferPositions( const std::vector<Vec3f> &positions );
00199     void                        bufferPositions( const Vec3f *positions, size_t count );
00200     void                        bufferNormals( const std::vector<Vec3f> &normals );
00201     void                        bufferTexCoords2d( size_t unit, const std::vector<Vec2f> &texCoords );
00202     void                        bufferTexCoords3d( size_t unit, const std::vector<Vec3f> &texCoords );
00203     void                        bufferColorsRGB( const std::vector<Color> &colors );
00204     void                        bufferColorsRGBA( const std::vector<ColorA> &colors );
00205     class VertexIter            mapVertexBuffer();
00206 
00207     Vbo&                getIndexVbo() const { return mObj->mBuffers[INDEX_BUFFER]; }
00208     Vbo&                getStaticVbo() const { return mObj->mBuffers[STATIC_BUFFER]; }
00209     Vbo&                getDynamicVbo() const { return mObj->mBuffers[DYNAMIC_BUFFER]; }
00210 
00211     void                setCustomStaticLocation( size_t internalIndex, GLuint location ) { mObj->mCustomStaticLocations[internalIndex] = location; }
00212     void                setCustomDynamicLocation( size_t internalIndex, GLuint location ) { mObj->mCustomDynamicLocations[internalIndex] = location; }
00213 
00214     size_t                      getTexCoordOffset( size_t unit ) const { return mObj->mTexCoordOffset[unit]; }
00215     void                        setTexCoordOffset( size_t unit, size_t aTexCoordOffset ) { mObj->mTexCoordOffset[unit] = aTexCoordOffset; } 
00216 
00218 
00219     typedef std::shared_ptr<Obj> VboMesh::*unspecified_bool_type;
00220     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &VboMesh::mObj; }
00221     void reset() { mObj.reset(); }
00223 
00224     class VertexIter {
00225      public:
00226         VertexIter( const VboMesh &mesh );
00227 
00228         void    setPosition( const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = v; }
00229         void    setPosition( float x, float y, float z ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = Vec3f( x, y, z ); }
00230         void    setNormal( const Vec3f &n ) { *(reinterpret_cast<Vec3f*>( &mPtr[mNormalOffset] )) = n; }
00231         void    setColorRGB( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBOffset] )) = n; }
00232         void    setColorRGBA( const ColorA &n ) { *(reinterpret_cast<ColorA*>( &mPtr[mColorRGBAOffset] )) = n; }
00233         void    setTexCoord2d0( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[0]] )) = t; }
00234         void    setTexCoord3d0( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[0]] )) = t; }
00235         void    setTexCoord2d1( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[1]] )) = t; }
00236         void    setTexCoord3d1( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[1]] )) = t; }
00237         void    setTexCoord2d2( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[2]] )) = t; }
00238         void    setTexCoord3d2( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[2]] )) = t; }
00239         void    setCustomFloat( size_t index, float v ) { *(reinterpret_cast<float*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00240         void    setCustomVec2f( size_t index, const Vec2f &v ) { *(reinterpret_cast<Vec2f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00241         void    setCustomVec3f( size_t index, const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00242         void    setCustomVec4f( size_t index, const Vec4f &v ) { *(reinterpret_cast<Vec4f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00243 
00244         void operator++() { mPtr += mStride; }
00245         bool    isDone() const { return mPtr < mDataEnd; }
00246         
00248         size_t      getIndex() const { return ( mPtr - mData ) / mStride; }
00250         size_t      getStride() const { return mStride; }
00252         void*       getPointer() const { return reinterpret_cast<void*>( mPtr ); }
00254         Vec3f*      getPositionPointer() const { return reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] ); }       
00255 
00256 //      VertexIter( const VertexIter &other ) { set( other ); } 
00257 //      VertexIter& operator=( const VertexIter &other ) { set( other ); return *this; }
00258         
00259      protected:
00260         void set( const VertexIter &other );
00261 
00262         struct Obj {
00263          public:
00264             Obj( const VboMesh &mesh );
00265             ~Obj();
00266             
00267             uint8_t                 *mData, *mDataEnd;
00268             std::vector<size_t>     mCustomOffsets;         
00269             Vbo                     mVbo;
00270         };
00271          
00272         std::shared_ptr<Obj>    mObj;
00273         uint8_t                 *mPtr;
00274         uint8_t                 *mData, *mDataEnd; // we cache these from the Obj to reduce dereferencing
00275         size_t                  mPositionOffset, mNormalOffset;
00276         size_t                  mColorRGBOffset, mColorRGBAOffset;
00277         size_t                  mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1];
00278         uint8_t                 mStride;
00279     };
00280 
00281  protected:
00282     void    initializeBuffers( bool staticDataPlanar );
00283 
00284     std::shared_ptr<Obj>        mObj;
00285 };
00286 
00287 class VboExc : public std::exception {
00288  public:
00289     virtual const char* what() const throw() { return "OpenGL Vbo exception"; }
00290 };
00291 
00292 class VboInvalidTargetExc : public VboExc {
00293  public:
00294     virtual const char* what() const throw() { return "OpenGL Vbo exception: Invalid Target"; }
00295 };
00296 
00297 class VboFailedMapExc : public VboExc {
00298  public:
00299     virtual const char* what() const throw() { return "OpenGL Vbo exception: Map failure"; } 
00300 };
00301 
00302 class VboFailedUnmapExc : public VboExc {
00303  public:
00304     virtual const char* what() const throw() { return "OpenGL Vbo exception: Unmap failure"; } 
00305 };
00306 
00307 } } // namespace cinder::gl