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 bufferColorsRGB( const std::vector<Color> &colors ); 00193 void bufferColorsRGBA( const std::vector<ColorA> &colors ); 00194 class VertexIter mapVertexBuffer(); 00195 00196 Vbo& getIndexVbo() const { return mObj->mBuffers[INDEX_BUFFER]; } 00197 Vbo& getStaticVbo() const { return mObj->mBuffers[STATIC_BUFFER]; } 00198 Vbo& getDynamicVbo() const { return mObj->mBuffers[DYNAMIC_BUFFER]; } 00199 00200 void setCustomStaticLocation( size_t internalIndex, GLuint location ) { mObj->mCustomStaticLocations[internalIndex] = location; } 00201 void setCustomDynamicLocation( size_t internalIndex, GLuint location ) { mObj->mCustomDynamicLocations[internalIndex] = location; } 00202 00203 size_t getTexCoordOffset( size_t unit ) const { return mObj->mTexCoordOffset[unit]; } 00204 void setTexCoordOffset( size_t unit, size_t aTexCoordOffset ) { mObj->mTexCoordOffset[unit] = aTexCoordOffset; } 00205 00207 00208 typedef std::shared_ptr<Obj> VboMesh::*unspecified_bool_type; 00209 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &VboMesh::mObj; } 00210 void reset() { mObj.reset(); } 00212 00213 class VertexIter { 00214 public: 00215 VertexIter( const VboMesh &mesh ); 00216 00217 void setPosition( const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = v; } 00218 void setPosition( float x, float y, float z ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = Vec3f( x, y, z ); } 00219 void setNormal( const Vec3f &n ) { *(reinterpret_cast<Vec3f*>( &mPtr[mNormalOffset] )) = n; } 00220 void setColorRGB( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBOffset] )) = n; } 00221 void setColorRGBA( const ColorA &n ) { *(reinterpret_cast<ColorA*>( &mPtr[mColorRGBAOffset] )) = n; } 00222 void setTexCoord2d0( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00223 void setTexCoord3d0( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00224 void setTexCoord2d1( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00225 void setTexCoord3d1( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00226 void setTexCoord2d2( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00227 void setTexCoord3d2( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00228 void setCustomFloat( size_t index, float v ) { *(reinterpret_cast<float*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00229 void setCustomVec2f( size_t index, const Vec2f &v ) { *(reinterpret_cast<Vec2f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00230 void setCustomVec3f( size_t index, const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00231 void setCustomVec4f( size_t index, const Vec4f &v ) { *(reinterpret_cast<Vec4f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00232 00233 void operator++() { mPtr += mStride; } 00234 bool isDone() const { return mPtr < mDataEnd; } 00235 00237 size_t getIndex() const { return ( mPtr - mData ) / mStride; } 00239 size_t getStride() const { return mStride; } 00241 void* getPointer() const { return reinterpret_cast<void*>( mPtr ); } 00243 Vec3f* getPositionPointer() const { return reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] ); } 00244 00245 // VertexIter( const VertexIter &other ) { set( other ); } 00246 // VertexIter& operator=( const VertexIter &other ) { set( other ); return *this; } 00247 00248 protected: 00249 void set( const VertexIter &other ); 00250 00251 struct Obj { 00252 public: 00253 Obj( const VboMesh &mesh ); 00254 ~Obj(); 00255 00256 uint8_t *mData, *mDataEnd; 00257 std::vector<size_t> mCustomOffsets; 00258 Vbo mVbo; 00259 }; 00260 00261 std::shared_ptr<Obj> mObj; 00262 uint8_t *mPtr; 00263 uint8_t *mData, *mDataEnd; // we cache these from the Obj to reduce dereferencing 00264 size_t mPositionOffset, mNormalOffset; 00265 size_t mColorRGBOffset, mColorRGBAOffset; 00266 size_t mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1]; 00267 uint8_t mStride; 00268 }; 00269 00270 protected: 00271 void initializeBuffers( bool staticDataPlanar ); 00272 00273 std::shared_ptr<Obj> mObj; 00274 }; 00275 00276 class VboExc : public std::exception { 00277 public: 00278 virtual const char* what() const throw() { return "OpenGL Vbo exception"; } 00279 }; 00280 00281 class VboInvalidTargetExc : public VboExc { 00282 public: 00283 virtual const char* what() const throw() { return "OpenGL Vbo exception: Invalid Target"; } 00284 }; 00285 00286 class VboFailedMapExc : public VboExc { 00287 public: 00288 virtual const char* what() const throw() { return "OpenGL Vbo exception: Map failure"; } 00289 }; 00290 00291 class VboFailedUnmapExc : public VboExc { 00292 public: 00293 virtual const char* what() const throw() { return "OpenGL Vbo exception: Unmap failure"; } 00294 }; 00295 00296 } } // namespace cinder::gl