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