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  public:
00072     enum { NONE, STATIC, DYNAMIC };
00073     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 };
00074     enum { ATTR_MAX_TEXTURE_UNIT = 3 };
00075 
00076     struct Layout {
00077         Layout() { initAttributes(); }
00078 
00080         bool    isDefaults() const { for( int a = 0; a < ATTR_TOTAL; ++a ) if( mAttributes[a] != NONE ) return false; return true; }
00081     
00082         bool    hasNormals() const { return hasDynamicNormals() || hasStaticNormals(); }
00083         bool    hasStaticNormals() const { return mAttributes[ATTR_NORMALS] == STATIC; }
00084         bool    hasDynamicNormals() const { return mAttributes[ATTR_NORMALS] == DYNAMIC; }
00085         void    setStaticNormals() { mAttributes[ATTR_NORMALS] = STATIC; }
00086         void    setDynamicNormals() { mAttributes[ATTR_NORMALS] = DYNAMIC; }        
00087 
00088         bool    hasColorsRGB() const { return hasDynamicColorsRGB() || hasStaticColorsRGB(); }
00089         bool    hasStaticColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == STATIC; }
00090         bool    hasDynamicColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == DYNAMIC; }
00091         void    setStaticColorsRGB() { mAttributes[ATTR_COLORS_RGB] = STATIC; mAttributes[ATTR_COLORS_RGBA] = NONE; }
00092         void    setDynamicColorsRGB() { mAttributes[ATTR_COLORS_RGB] = DYNAMIC; mAttributes[ATTR_COLORS_RGBA] = NONE; }     
00093 
00094         bool    hasColorsRGBA() const { return hasDynamicColorsRGBA() || hasStaticColorsRGBA(); }
00095         bool    hasStaticColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == STATIC; }
00096         bool    hasDynamicColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == DYNAMIC; }
00097         void    setStaticColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = STATIC; mAttributes[ATTR_COLORS_RGB] = NONE; }
00098         void    setDynamicColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = DYNAMIC; mAttributes[ATTR_COLORS_RGB] = NONE; }        
00099         
00100         bool    hasTexCoords2d( size_t unit = 0 ) const { return hasDynamicTexCoords2d( unit ) || hasStaticTexCoords2d( unit ); }
00101         bool    hasStaticTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == STATIC; }      
00102         bool    hasDynamicTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == DYNAMIC; }
00103         void    setStaticTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; }
00104         void    setDynamicTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; }
00106         bool    hasStaticTexCoords() const;
00108         bool    hasDynamicTexCoords() const;
00110         bool    hasTexCoords( size_t unit ) const { return ( mAttributes[ATTR_TEXCOORDS2D_0 + unit] != NONE ) || ( mAttributes[ATTR_TEXCOORDS3D_0 + unit] != NONE ); }
00111 
00112         bool    hasTexCoords3d( size_t unit = 0 ) const { return hasDynamicTexCoords3d( unit ) || hasStaticTexCoords3d( unit ); }
00113         bool    hasStaticTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == STATIC; }      
00114         bool    hasDynamicTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == DYNAMIC; }
00115         void    setStaticTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; }
00116         void    setDynamicTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; }
00117 
00118         bool    hasIndices() const { return hasStaticIndices() || hasDynamicIndices(); }
00119         bool    hasStaticIndices() const { return mAttributes[ATTR_INDICES] == STATIC; }
00120         bool    hasDynamicIndices() const { return mAttributes[ATTR_INDICES] == DYNAMIC; }
00121         void    setStaticIndices() { mAttributes[ATTR_INDICES] = STATIC; }
00122         void    setDynamicIndices() { mAttributes[ATTR_INDICES] = DYNAMIC; }
00123 
00124         bool    hasPositions() const { return hasStaticPositions() || hasDynamicPositions(); }
00125         bool    hasStaticPositions() const { return mAttributes[ATTR_POSITIONS] == STATIC; }
00126         bool    hasDynamicPositions() const { return mAttributes[ATTR_POSITIONS] == DYNAMIC; }
00127         void    setStaticPositions() { mAttributes[ATTR_POSITIONS] = STATIC; }
00128         void    setDynamicPositions() { mAttributes[ATTR_POSITIONS] = DYNAMIC; }
00129         
00130         enum CustomAttr { CUSTOM_ATTR_FLOAT, CUSTOM_ATTR_FLOAT2, CUSTOM_ATTR_FLOAT3, CUSTOM_ATTR_FLOAT4, TOTAL_CUSTOM_ATTR_TYPES };
00131         static int sCustomAttrSizes[TOTAL_CUSTOM_ATTR_TYPES];
00132         static GLint sCustomAttrNumComponents[TOTAL_CUSTOM_ATTR_TYPES];
00133         static GLenum sCustomAttrTypes[TOTAL_CUSTOM_ATTR_TYPES];
00134         void    addDynamicCustomFloat() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT, 0 ) ); }
00135         void    addDynamicCustomVec2f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT2, 0 ) ); }
00136         void    addDynamicCustomVec3f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT3, 0 ) ); }
00137         void    addDynamicCustomVec4f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT4, 0 ) ); }
00138 
00139         int                                             mAttributes[ATTR_TOTAL];
00140         std::vector<std::pair<CustomAttr,size_t> >      mCustomDynamic, mCustomStatic; // pair of <types,offset>
00141         
00142      private:
00143         void initAttributes() { for( int a = 0; a < ATTR_TOTAL; ++a ) mAttributes[a] = NONE; }
00144     };
00145 
00146     enum            { INDEX_BUFFER = 0, STATIC_BUFFER, DYNAMIC_BUFFER, TOTAL_BUFFERS };
00147     
00148   protected:
00149     struct Obj {
00150         size_t          mNumIndices, mNumVertices;  
00151 
00152         Vbo             mBuffers[TOTAL_BUFFERS];
00153         size_t          mPositionOffset;
00154         size_t          mNormalOffset;
00155         size_t          mColorRGBOffset, mColorRGBAOffset;      
00156         size_t          mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1];
00157         size_t          mStaticStride, mDynamicStride;  
00158         GLenum          mPrimitiveType;
00159         Layout          mLayout;
00160         std::vector<GLint>      mCustomStaticLocations;
00161         std::vector<GLint>      mCustomDynamicLocations;
00162     };
00163 
00164   public:
00165     class VertexIter;
00166  
00167     VboMesh() {}
00168     explicit VboMesh( const TriMesh &triMesh, Layout layout = Layout() );
00169     explicit VboMesh( const TriMesh2d &triMesh, Layout layout = Layout() );
00170     /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Dynamic data is stored interleaved and static data is planar. **/
00171     VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType );
00172     /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Accepts pointers to preexisting buffers, which may be NULL to request allocation **/
00173     VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType, Vbo *indexBuffer, Vbo *staticBuffer, Vbo *dynamicBuffer );
00174 
00175     size_t  getNumIndices() const { return mObj->mNumIndices; }
00176     size_t  getNumVertices() const { return mObj->mNumVertices; }
00177     GLenum  getPrimitiveType() const { return mObj->mPrimitiveType; }
00178     
00179     const Layout&   getLayout() const { return mObj->mLayout; }
00180 
00181     void            bindIndexBuffer() const;
00182     void            enableClientStates() const;
00183     void            disableClientStates() const;
00184     void            bindAllData() const;
00185     static void     unbindBuffers();
00186 
00187     void                        bufferIndices( const std::vector<uint32_t> &indices );
00188     void                        bufferPositions( const std::vector<Vec3f> &positions );
00189     void                        bufferPositions( const Vec3f *positions, size_t count );
00190     void                        bufferNormals( const std::vector<Vec3f> &normals );
00191     void                        bufferTexCoords2d( size_t unit, const std::vector<Vec2f> &texCoords );
00192     void                        bufferTexCoords3d( size_t unit, const std::vector<Vec3f> &texCoords );
00193     void                        bufferColorsRGB( const std::vector<Color> &colors );
00194     void                        bufferColorsRGBA( const std::vector<ColorA> &colors );
00195     class VertexIter            mapVertexBuffer();
00196 
00197     Vbo&                getIndexVbo() const { return mObj->mBuffers[INDEX_BUFFER]; }
00198     Vbo&                getStaticVbo() const { return mObj->mBuffers[STATIC_BUFFER]; }
00199     Vbo&                getDynamicVbo() const { return mObj->mBuffers[DYNAMIC_BUFFER]; }
00200 
00201     void                setCustomStaticLocation( size_t internalIndex, GLuint location ) { mObj->mCustomStaticLocations[internalIndex] = location; }
00202     void                setCustomDynamicLocation( size_t internalIndex, GLuint location ) { mObj->mCustomDynamicLocations[internalIndex] = location; }
00203 
00204     size_t                      getTexCoordOffset( size_t unit ) const { return mObj->mTexCoordOffset[unit]; }
00205     void                        setTexCoordOffset( size_t unit, size_t aTexCoordOffset ) { mObj->mTexCoordOffset[unit] = aTexCoordOffset; } 
00206 
00208 
00209     typedef std::shared_ptr<Obj> VboMesh::*unspecified_bool_type;
00210     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &VboMesh::mObj; }
00211     void reset() { mObj.reset(); }
00213 
00214     class VertexIter {
00215      public:
00216         VertexIter( const VboMesh &mesh );
00217 
00218         void    setPosition( const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = v; }
00219         void    setPosition( float x, float y, float z ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = Vec3f( x, y, z ); }
00220         void    setNormal( const Vec3f &n ) { *(reinterpret_cast<Vec3f*>( &mPtr[mNormalOffset] )) = n; }
00221         void    setColorRGB( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBOffset] )) = n; }
00222         void    setColorRGBA( const ColorA &n ) { *(reinterpret_cast<ColorA*>( &mPtr[mColorRGBAOffset] )) = n; }
00223         void    setTexCoord2d0( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[0]] )) = t; }
00224         void    setTexCoord3d0( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[0]] )) = t; }
00225         void    setTexCoord2d1( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[1]] )) = t; }
00226         void    setTexCoord3d1( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[1]] )) = t; }
00227         void    setTexCoord2d2( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[2]] )) = t; }
00228         void    setTexCoord3d2( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[2]] )) = t; }
00229         void    setCustomFloat( size_t index, float v ) { *(reinterpret_cast<float*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00230         void    setCustomVec2f( size_t index, const Vec2f &v ) { *(reinterpret_cast<Vec2f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00231         void    setCustomVec3f( size_t index, const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00232         void    setCustomVec4f( size_t index, const Vec4f &v ) { *(reinterpret_cast<Vec4f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; }
00233 
00234         void operator++() { mPtr += mStride; }
00235         bool    isDone() const { return mPtr < mDataEnd; }
00236         
00238         size_t      getIndex() const { return ( mPtr - mData ) / mStride; }
00240         size_t      getStride() const { return mStride; }
00242         void*       getPointer() const { return reinterpret_cast<void*>( mPtr ); }
00244         Vec3f*      getPositionPointer() const { return reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] ); }       
00245 
00246 //      VertexIter( const VertexIter &other ) { set( other ); } 
00247 //      VertexIter& operator=( const VertexIter &other ) { set( other ); return *this; }
00248         
00249      protected:
00250         void set( const VertexIter &other );
00251 
00252         struct Obj {
00253          public:
00254             Obj( const VboMesh &mesh );
00255             ~Obj();
00256             
00257             uint8_t                 *mData, *mDataEnd;
00258             std::vector<size_t>     mCustomOffsets;         
00259             Vbo                     mVbo;
00260         };
00261          
00262         std::shared_ptr<Obj>    mObj;
00263         uint8_t                 *mPtr;
00264         uint8_t                 *mData, *mDataEnd; // we cache these from the Obj to reduce dereferencing
00265         size_t                  mPositionOffset, mNormalOffset;
00266         size_t                  mColorRGBOffset, mColorRGBAOffset;
00267         size_t                  mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1];
00268         uint8_t                 mStride;
00269     };
00270 
00271  protected:
00272     void    initializeBuffers( bool staticDataPlanar );
00273 
00274     std::shared_ptr<Obj>        mObj;
00275 };
00276 
00277 class VboExc : public std::exception {
00278  public:
00279     virtual const char* what() const throw() { return "OpenGL Vbo exception"; }
00280 };
00281 
00282 class VboInvalidTargetExc : public VboExc {
00283  public:
00284     virtual const char* what() const throw() { return "OpenGL Vbo exception: Invalid Target"; }
00285 };
00286 
00287 class VboFailedMapExc : public VboExc {
00288  public:
00289     virtual const char* what() const throw() { return "OpenGL Vbo exception: Map failure"; } 
00290 };
00291 
00292 class VboFailedUnmapExc : public VboExc {
00293  public:
00294     virtual const char* what() const throw() { return "OpenGL Vbo exception: Unmap failure"; } 
00295 };
00296 
00297 } } // namespace cinder::gl