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 shared_ptr<Obj> mObj; 00060 00061 public: 00063 00064 typedef shared_ptr<Obj> Vbo::*unspecified_bool_type; 00065 operator unspecified_bool_type() { 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 /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Dynamic data is stored interleaved and static data is planar. **/ 00170 VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType ); 00171 /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Accepts pointers to preexisting buffers, which may be NULL to request allocation **/ 00172 VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType, Vbo *indexBuffer, Vbo *staticBuffer, Vbo *dynamicBuffer ); 00173 00174 size_t getNumIndices() const { return mObj->mNumIndices; } 00175 size_t getNumVertices() const { return mObj->mNumVertices; } 00176 GLenum getPrimitiveType() const { return mObj->mPrimitiveType; } 00177 00178 const Layout& getLayout() const { return mObj->mLayout; } 00179 00180 void bindIndexBuffer() const; 00181 void enableClientStates() const; 00182 void disableClientStates() const; 00183 void bindAllData() const; 00184 static void unbindBuffers(); 00185 00186 void bufferIndices( const std::vector<uint32_t> &indices ); 00187 void bufferPositions( const std::vector<Vec3f> &normals ); 00188 void bufferNormals( const std::vector<Vec3f> &normals ); 00189 void bufferTexCoords2d( size_t unit, const std::vector<Vec2f> &texCoords ); 00190 class VertexIter mapVertexBuffer(); 00191 00192 Vbo& getIndexVbo() const { return mObj->mBuffers[INDEX_BUFFER]; } 00193 Vbo& getStaticVbo() const { return mObj->mBuffers[STATIC_BUFFER]; } 00194 Vbo& getDynamicVbo() const { return mObj->mBuffers[DYNAMIC_BUFFER]; } 00195 00196 void setCustomStaticLocation( size_t internalIndex, GLuint location ) { mObj->mCustomStaticLocations[internalIndex] = location; } 00197 void setCustomDynamicLocation( size_t internalIndex, GLuint location ) { mObj->mCustomDynamicLocations[internalIndex] = location; } 00198 00199 size_t getTexCoordOffset( size_t unit ) const { return mObj->mTexCoordOffset[unit]; } 00200 void setTexCoordOffset( size_t unit, size_t aTexCoordOffset ) { mObj->mTexCoordOffset[unit] = aTexCoordOffset; } 00201 00203 00204 VboMesh( const VboMesh &other ) { mObj = other.mObj; } 00205 VboMesh& operator=( const VboMesh &other ) { mObj = other.mObj; return *this; } 00206 bool operator==( const VboMesh &other ) { return mObj == other.mObj; } 00207 typedef shared_ptr<Obj> VboMesh::*unspecified_bool_type; 00208 operator unspecified_bool_type() { return ( mObj.get() == 0 ) ? 0 : &VboMesh::mObj; } 00209 void reset() { mObj.reset(); } 00211 00212 class VertexIter { 00213 public: 00214 VertexIter( const VboMesh &mesh ); 00215 00216 void setPosition( const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = v; } 00217 void setPosition( float x, float y, float z ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = Vec3f( x, y, z ); } 00218 void setNormal( const Vec3f &n ) { *(reinterpret_cast<Vec3f*>( &mPtr[mNormalOffset] )) = n; } 00219 void setColorRGB( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBOffset] )) = n; } 00220 void setColorRGBA( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBAOffset] )) = n; } 00221 void setTexCoord2d0( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00222 void setTexCoord3d0( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00223 void setTexCoord2d1( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00224 void setTexCoord3d1( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00225 void setTexCoord2d2( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00226 void setTexCoord3d2( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00227 void setCustomFloat( size_t index, float v ) { *(reinterpret_cast<float*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00228 void setCustomVec2f( size_t index, const Vec2f &v ) { *(reinterpret_cast<Vec2f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00229 void setCustomVec3f( size_t index, const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00230 void setCustomVec4f( size_t index, const Vec4f &v ) { *(reinterpret_cast<Vec4f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00231 00232 void operator++() { mPtr += mStride; } 00233 bool isDone() const { return mPtr < mDataEnd; } 00234 00236 size_t getIndex() const { return ( mPtr - mData ) / mStride; } 00238 size_t getStride() const { return mStride; } 00240 void* getPointer() const { return reinterpret_cast<void*>( mPtr ); } 00242 Vec3f* getPositionPointer() const { return reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] ); } 00243 00244 // VertexIter( const VertexIter &other ) { set( other ); } 00245 // VertexIter& operator=( const VertexIter &other ) { set( other ); return *this; } 00246 00247 protected: 00248 void set( const VertexIter &other ); 00249 00250 struct Obj { 00251 public: 00252 Obj( const VboMesh &mesh ); 00253 ~Obj(); 00254 00255 uint8_t *mData, *mDataEnd; 00256 std::vector<size_t> mCustomOffsets; 00257 Vbo mVbo; 00258 }; 00259 00260 shared_ptr<Obj> mObj; 00261 uint8_t *mPtr; 00262 uint8_t *mData, *mDataEnd; // we cache these from the Obj to reduce dereferencing 00263 size_t mPositionOffset, mNormalOffset; 00264 size_t mColorRGBOffset, mColorRGBAOffset; 00265 size_t mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1]; 00266 uint8_t mStride; 00267 }; 00268 00269 protected: 00270 void initializeBuffers( bool staticDataPlanar ); 00271 00272 shared_ptr<Obj> mObj; 00273 }; 00274 00275 class VboExc : public std::exception { 00276 public: 00277 virtual const char* what() const throw() { return "OpenGL Vbo exception"; } 00278 }; 00279 00280 class VboInvalidTargetExc : public VboExc { 00281 public: 00282 virtual const char* what() const throw() { return "OpenGL Vbo exception: Invalid Target"; } 00283 }; 00284 00285 class VboFailedMapExc : public VboExc { 00286 public: 00287 virtual const char* what() const throw() { return "OpenGL Vbo exception: Map failure"; } 00288 }; 00289 00290 class VboFailedUnmapExc : public VboExc { 00291 public: 00292 virtual const char* what() const throw() { return "OpenGL Vbo exception: Unmap failure"; } 00293 }; 00294 00295 } } // namespace cinder::gl